<commit_before>#include "AliHBTReaderESD.h"
//____________________________________________________________________
//////////////////////////////////////////////////////////////////////
//                                                                  //
// class AliHBTReaderESD                                            //
//                                                                  //
// reader for ALICE Event Summary Data (ESD).                       //
//                                                                  //
// Piotr.Skowronski@cern.ch                                         //
//                                                                  //
//////////////////////////////////////////////////////////////////////

#include <TPDGCode.h>
#include <TString.h>
#include <TObjString.h>
#include <TTree.h>
#include <TFile.h>
#include <TParticle.h>

#include <AliRunLoader.h>
#include <AliStack.h>
#include <AliESDtrack.h>
#include <AliESD.h>

#include "AliHBTRun.h"
#include "AliHBTEvent.h"
#include "AliHBTParticle.h"
#include "AliHBTParticleCut.h"

ClassImp(AliHBTReaderESD)

AliHBTReaderESD::AliHBTReaderESD(const Char_t* esdfilename, const Char_t* galfilename):
 fESDFileName(esdfilename),
 fGAlFileName(galfilename),
 fFile(0x0),
 fRunLoader(0x0),
 fReadParticles(kFALSE)
{
  //cosntructor
  if ( ((Int_t)kNSpecies) != ((Int_t)AliESDtrack::kSPECIES))
    Fatal("AliHBTReaderESD","ESD defintions probobly changed. Ask Youra.");
}
/********************************************************************/

AliHBTReaderESD::AliHBTReaderESD(TObjArray* dirs,const Char_t* esdfilename, const Char_t* galfilename):
 AliHBTReader(dirs),
 fESDFileName(esdfilename),
 fGAlFileName(galfilename),
 fFile(0x0),
 fRunLoader(0x0),
 fReadParticles(kFALSE)
{
  //cosntructor
  if ( ((Int_t)kNSpecies) != ((Int_t)AliESDtrack::kSPECIES))
    Fatal("AliHBTReaderESD","ESD defintions probobly changed. Ask Youra.");
}
/********************************************************************/

AliHBTReaderESD::~AliHBTReaderESD()
{
 //desctructor
  delete fRunLoader;
  delete fFile;
}
/**********************************************************/
Int_t AliHBTReaderESD::ReadNext()
{
//reads next event from fFile

  //****** Tentative particle type "concentrations"
  static const Double_t concentr[5]={0.05, 0., 0.85, 0.10, 0.05};

  Double_t pidtable[kNSpecies];//array used for reading pid probabilities from ESD track
  Double_t w[kNSpecies];
  Double_t mom[3];//momentum
  Double_t pos[3];//position

  if (AliHBTParticle::fgDebug)
    Info("ReadNext","Entered");

  TDatabasePDG* pdgdb = TDatabasePDG::Instance();
  if (pdgdb == 0x0)
   {
     Error("Next","Can not get PDG Database Instance.");
     return 1;
   }

  if (fParticlesEvent == 0x0)  fParticlesEvent = new AliHBTEvent();
  if (fTracksEvent == 0x0)  fTracksEvent = new AliHBTEvent();

  fParticlesEvent->Reset();
  fTracksEvent->Reset();

  do  //do{}while; is OK even if 0 dirs specified. In that case we try to read from "./"
   {
     if (fFile == 0x0)
      {
       fFile = OpenFile(fCurrentDir);//rl is opened here
       if (fFile == 0x0)
         {
           Error("ReadNext","Cannot get fFile for dir no. %d",fCurrentDir);
           fCurrentDir++;
           continue;
         }
       fCurrentEvent = 0;
      }

     //try to read
     TString esdname;
     esdname+=fCurrentEvent;
     AliESD* esd = dynamic_cast<AliESD*>(fFile->Get(esdname));
     if (esd == 0x0)
      {
        if (AliHBTParticle::fgDebug > 2 )
          {
            Info("ReadNext","Can not find ESD object named %s.",esdname.Data());
          }
        fCurrentDir++;
        delete fFile;//we have to assume there is no more ESD objects in the fFile
        delete fRunLoader;
        fFile = 0x0;
        fRunLoader = 0x0;
        continue;
      }
     AliStack* stack = 0x0;
     if (fReadParticles && fRunLoader)
      {
        fRunLoader->GetEvent(fCurrentEvent);
        stack = fRunLoader->Stack();
      }
     Info("ReadNext","Reading Event %d",fCurrentEvent);

     Int_t ntr = esd->GetNumberOfTracks();
     Info("ReadNext","Found %d tracks.",ntr);
     for (Int_t i = 0;i<ntr; i++)
      {
        AliESDtrack *esdtrack = esd->GetTrack(i);
        if (esdtrack == 0x0)
         {
           Error("Next","Can not get track %d", i);
           continue;
         }

        //if (esdtrack->HasVertexParameters() == kFALSE)
        if ((esdtrack->GetStatus() & AliESDtrack::kITSrefit) == kFALSE)
         {
           if (AliHBTParticle::fgDebug > 2)
             Info("ReadNext","Particle skipped: Data at vertex not available.");
           continue;
         }

        if ((esdtrack->GetStatus()&AliESDtrack::kESDpid) == kFALSE)
         {
           if (AliHBTParticle::fgDebug > 2)
             Info("ReadNext","Particle skipped: PID BIT is not set.");
           continue;
         }

        esdtrack->GetESDpid(pidtable);
        //esdtrack->GetVertexPxPyPz(mom[0],mom[1],mom[2]);
        esdtrack->GetPxPyPz(mom);
        //esdtrack->GetVertexXYZ(pos[0],pos[1],pos[2]);
        esdtrack->GetXYZ(pos);

        Double_t extx;
        Double_t extp[5];
        esdtrack->GetExternalParameters(extx,extp);

        Int_t charge = (extp[4] > 0)?-1:1;//if curvature=-charg/Pt is positive charge is negative

        //Particle from kinematics
        AliHBTParticle* particle = 0;
        Bool_t keeppart = kFALSE;
        if ( fReadParticles && stack  )
         {
           if (esdtrack->GetLabel() < 0) continue;//this is fake -  we are not able to match any track
           TParticle *p = stack->Particle(esdtrack->GetLabel());
           if (p==0x0)
            {
              Error("ReadNext","Can not find track with such label.");
              continue;
            }
//           if(p->GetPdgCode()<0) charge = -1;
           particle = new AliHBTParticle(*p,i);

         }

        //Here we apply Bayes' formula
        Double_t rc=0.;
        for (Int_t s=0; s<AliESDtrack::kSPECIES; s++) rc+=concentr[s]*pidtable[s];
        if (rc==0.0)
         {
           if (AliHBTParticle::fgDebug > 2)
             Info("ReadNext","Particle rejected since total bayessian PID probab. is zero.");
           continue;
         }

        for (Int_t s=0; s<AliESDtrack::kSPECIES; s++) w[s]=concentr[s]*pidtable[s]/rc;

        if (AliHBTParticle::fgDebug > 4)
         {
           Info("ReadNext","###########################################################################");
           Info("ReadNext","Momentum: %f %f %f",mom[0],mom[1],mom[2]);
           Info("ReadNext","Position: %f %f %f",pos[0],pos[1],pos[2]);
           TString msg("Pid list got from track:");
           for (Int_t s = 0;s<kNSpecies;s++)
            {
              msg+="\n    ";
              msg+=s;
              msg+="(";
              msg+=charge*GetSpeciesPdgCode((ESpecies)s);
              msg+="): ";
              msg+=w[s];
              msg+=" (";
              msg+=pidtable[s];
              msg+=")";
            }
           Info("ReadNext","%s",msg.Data());
         }//if (AliHBTParticle::fgDebug>4)

        for (Int_t s = 0; s<kNSpecies; s++)
         {
           Float_t pp = w[s];
           if (pp == 0.0) continue;

           Int_t pdgcode = charge*GetSpeciesPdgCode((ESpecies)s);
           if(Pass(pdgcode)) continue; //check if we are intersted with particles of this type

           Double_t mass = pdgdb->GetParticle(pdgcode)->Mass();
           Double_t tEtot = TMath::Sqrt( mom[0]*mom[0] + mom[1]*mom[1] + mom[2]*mom[2] + mass*mass);//total energy of the track

           AliHBTParticle* track = new AliHBTParticle(pdgcode, w[s],i,
                                                      mom[0], mom[1], mom[2], tEtot,
                                                      pos[0], pos[1], pos[2], 0.);
           //copy probabilitis of other species (if not zero)
           for (Int_t k = 0; k<kNSpecies; k++)
            {
              if (k == s) continue;
              if (w[k] == 0.0) continue;
              track->SetPIDprobability(charge*GetSpeciesPdgCode( (ESpecies)k ),w[k]);
            }
           if(Pass(track))//check if meets all criteria of any of our cuts
                          //if it does not delete it and take next good track
            {
              delete track;
              continue;
            }

           fTracksEvent->AddParticle(track);
           if (particle) fParticlesEvent->AddParticle(particle);
           keeppart = kTRUE;

           if (AliHBTParticle::fgDebug > 4 )
            {
              Info("ReadNext","\n\nAdding Particle with incarnation %d",pdgcode);
              track->Print();
            }
         }//for (Int_t s = 0; s<kNSpecies; s++)

        if (keeppart == kFALSE) delete particle;//particle was not stored in event

      }//for (Int_t i = 0;i<ntr; i++)  -- loop over tracks

     Info("ReadNext","Read %d tracks and %d particles from event %d (event %d in dir %d).",
            fTracksEvent->GetNumberOfParticles(), fParticlesEvent->GetNumberOfParticles(),
            fNEventsRead,fCurrentEvent,fCurrentDir);

     fCurrentEvent++;
     fNEventsRead++;
     delete esd;
     return 0;//success -> read one event
   }while(fCurrentDir < GetNumberOfDirs());//end of loop over directories specified in fDirs Obj Array

  return 1; //no more directories to read
}
/**********************************************************/
void AliHBTReaderESD::Rewind()
{
  //rewinds reading
  delete fFile;
  fFile = 0;
  delete fRunLoader;
  fCurrentDir = 0;
  fNEventsRead = 0;
  fCurrentEvent++;
}
/**********************************************************/

TFile* AliHBTReaderESD::OpenFile(Int_t n)
{
//opens fFile with kine tree

 const TString& dirname = GetDirName(n);
 if (dirname == "")
  {
   Error("OpenFiles","Can not get directory name");
   return 0x0;
  }
 TString filename = dirname +"/"+ fESDFileName;
 TFile *ret = TFile::Open(filename.Data());

 if ( ret == 0x0)
  {
    Error("OpenFiles","Can't open fFile %s",filename.Data());
    return 0x0;
  }
 if (!ret->IsOpen())
  {
    Error("OpenFiles","Can't open fFile  %s",filename.Data());
    return 0x0;
  }

 if (fReadParticles)
  {
   fRunLoader = AliRunLoader::Open(dirname +"/"+ fGAlFileName);
   if (fRunLoader == 0x0)
    {
      Error("OpenFiles","Can't get RunLoader for directory %s",dirname.Data());
      delete ret;
      return 0x0;
    }
   fRunLoader->LoadHeader();
   if (fRunLoader->LoadKinematics())
    {
      Error("Next","Error occured while loading kinematics.");
      delete fRunLoader;
      delete ret;
      return 0x0;
    }
  }
 return ret;
}
/**********************************************************/

Int_t AliHBTReaderESD::GetSpeciesPdgCode(ESpecies spec)//skowron
{
  //returns pdg code from the PID index
  //ask jura about charge
  switch (spec)
   {
     case kESDElectron:
       return kPositron;
       break;
     case kESDMuon:
       return kMuonPlus;
       break;
     case kESDPion:
       return kPiPlus;
       break;
     case kESDKaon:
       return kKPlus;
       break;
     case kESDProton:
       return kProton;
       break;
     default:
       ::Warning("GetSpeciesPdgCode","Specie with number %d is not defined.",(Int_t)spec);
       break;
   }
  return 0;
}
<commit_msg>AliHBTParticle::fgDebug --> AliHBTParticle::GetDebug()<commit_after>#include "AliHBTReaderESD.h"
//____________________________________________________________________
//////////////////////////////////////////////////////////////////////
//                                                                  //
// class AliHBTReaderESD                                            //
//                                                                  //
// reader for ALICE Event Summary Data (ESD).                       //
//                                                                  //
// Piotr.Skowronski@cern.ch                                         //
//                                                                  //
//////////////////////////////////////////////////////////////////////

#include <TPDGCode.h>
#include <TString.h>
#include <TObjString.h>
#include <TTree.h>
#include <TFile.h>
#include <TParticle.h>

#include <AliRunLoader.h>
#include <AliStack.h>
#include <AliESDtrack.h>
#include <AliESD.h>

#include "AliHBTRun.h"
#include "AliHBTEvent.h"
#include "AliHBTParticle.h"
#include "AliHBTParticleCut.h"

ClassImp(AliHBTReaderESD)

AliHBTReaderESD::AliHBTReaderESD(const Char_t* esdfilename, const Char_t* galfilename):
 fESDFileName(esdfilename),
 fGAlFileName(galfilename),
 fFile(0x0),
 fRunLoader(0x0),
 fReadParticles(kFALSE)
{
  //cosntructor
  if ( ((Int_t)kNSpecies) != ((Int_t)AliESDtrack::kSPECIES))
    Fatal("AliHBTReaderESD","ESD defintions probobly changed. Ask Youra.");
}
/********************************************************************/

AliHBTReaderESD::AliHBTReaderESD(TObjArray* dirs,const Char_t* esdfilename, const Char_t* galfilename):
 AliHBTReader(dirs),
 fESDFileName(esdfilename),
 fGAlFileName(galfilename),
 fFile(0x0),
 fRunLoader(0x0),
 fReadParticles(kFALSE)
{
  //cosntructor
  if ( ((Int_t)kNSpecies) != ((Int_t)AliESDtrack::kSPECIES))
    Fatal("AliHBTReaderESD","ESD defintions probobly changed. Ask Youra.");
}
/********************************************************************/

AliHBTReaderESD::~AliHBTReaderESD()
{
 //desctructor
  delete fRunLoader;
  delete fFile;
}
/**********************************************************/
Int_t AliHBTReaderESD::ReadNext()
{
//reads next event from fFile

  //****** Tentative particle type "concentrations"
  static const Double_t concentr[5]={0.05, 0., 0.85, 0.10, 0.05};

  Double_t pidtable[kNSpecies];//array used for reading pid probabilities from ESD track
  Double_t w[kNSpecies];
  Double_t mom[3];//momentum
  Double_t pos[3];//position

  if (AliHBTParticle::GetDebug())
    Info("ReadNext","Entered");

  TDatabasePDG* pdgdb = TDatabasePDG::Instance();
  if (pdgdb == 0x0)
   {
     Error("Next","Can not get PDG Database Instance.");
     return 1;
   }

  if (fParticlesEvent == 0x0)  fParticlesEvent = new AliHBTEvent();
  if (fTracksEvent == 0x0)  fTracksEvent = new AliHBTEvent();

  fParticlesEvent->Reset();
  fTracksEvent->Reset();

  do  //do{}while; is OK even if 0 dirs specified. In that case we try to read from "./"
   {
     if (fFile == 0x0)
      {
       fFile = OpenFile(fCurrentDir);//rl is opened here
       if (fFile == 0x0)
         {
           Error("ReadNext","Cannot get fFile for dir no. %d",fCurrentDir);
           fCurrentDir++;
           continue;
         }
       fCurrentEvent = 0;
      }

     //try to read
     TString esdname;
     esdname+=fCurrentEvent;
     AliESD* esd = dynamic_cast<AliESD*>(fFile->Get(esdname));
     if (esd == 0x0)
      {
        if (AliHBTParticle::GetDebug() > 2 )
          {
            Info("ReadNext","Can not find ESD object named %s.",esdname.Data());
          }
        fCurrentDir++;
        delete fFile;//we have to assume there is no more ESD objects in the fFile
        delete fRunLoader;
        fFile = 0x0;
        fRunLoader = 0x0;
        continue;
      }
     AliStack* stack = 0x0;
     if (fReadParticles && fRunLoader)
      {
        fRunLoader->GetEvent(fCurrentEvent);
        stack = fRunLoader->Stack();
      }
     Info("ReadNext","Reading Event %d",fCurrentEvent);

     Int_t ntr = esd->GetNumberOfTracks();
     Info("ReadNext","Found %d tracks.",ntr);
     for (Int_t i = 0;i<ntr; i++)
      {
        AliESDtrack *esdtrack = esd->GetTrack(i);
        if (esdtrack == 0x0)
         {
           Error("Next","Can not get track %d", i);
           continue;
         }

        //if (esdtrack->HasVertexParameters() == kFALSE)
        if ((esdtrack->GetStatus() & AliESDtrack::kITSrefit) == kFALSE)
         {
           if (AliHBTParticle::GetDebug() > 2)
             Info("ReadNext","Particle skipped: Data at vertex not available.");
           continue;
         }

        if ((esdtrack->GetStatus()&AliESDtrack::kESDpid) == kFALSE)
         {
           if (AliHBTParticle::GetDebug() > 2)
             Info("ReadNext","Particle skipped: PID BIT is not set.");
           continue;
         }

        esdtrack->GetESDpid(pidtable);
        //esdtrack->GetVertexPxPyPz(mom[0],mom[1],mom[2]);
        esdtrack->GetPxPyPz(mom);
        //esdtrack->GetVertexXYZ(pos[0],pos[1],pos[2]);
        esdtrack->GetXYZ(pos);

        Double_t extx;
        Double_t extp[5];
        esdtrack->GetExternalParameters(extx,extp);

        Int_t charge = (extp[4] > 0)?-1:1;//if curvature=-charg/Pt is positive charge is negative

        //Particle from kinematics
        AliHBTParticle* particle = 0;
        Bool_t keeppart = kFALSE;
        if ( fReadParticles && stack  )
         {
           if (esdtrack->GetLabel() < 0) continue;//this is fake -  we are not able to match any track
           TParticle *p = stack->Particle(esdtrack->GetLabel());
           if (p==0x0)
            {
              Error("ReadNext","Can not find track with such label.");
              continue;
            }
//           if(p->GetPdgCode()<0) charge = -1;
           particle = new AliHBTParticle(*p,i);

         }

        //Here we apply Bayes' formula
        Double_t rc=0.;
        for (Int_t s=0; s<AliESDtrack::kSPECIES; s++) rc+=concentr[s]*pidtable[s];
        if (rc==0.0)
         {
           if (AliHBTParticle::GetDebug() > 2)
             Info("ReadNext","Particle rejected since total bayessian PID probab. is zero.");
           continue;
         }

        for (Int_t s=0; s<AliESDtrack::kSPECIES; s++) w[s]=concentr[s]*pidtable[s]/rc;

        if (AliHBTParticle::GetDebug() > 4)
         {
           Info("ReadNext","###########################################################################");
           Info("ReadNext","Momentum: %f %f %f",mom[0],mom[1],mom[2]);
           Info("ReadNext","Position: %f %f %f",pos[0],pos[1],pos[2]);
           TString msg("Pid list got from track:");
           for (Int_t s = 0;s<kNSpecies;s++)
            {
              msg+="\n    ";
              msg+=s;
              msg+="(";
              msg+=charge*GetSpeciesPdgCode((ESpecies)s);
              msg+="): ";
              msg+=w[s];
              msg+=" (";
              msg+=pidtable[s];
              msg+=")";
            }
           Info("ReadNext","%s",msg.Data());
         }//if (AliHBTParticle::GetDebug()>4)

        for (Int_t s = 0; s<kNSpecies; s++)
         {
           Float_t pp = w[s];
           if (pp == 0.0) continue;

           Int_t pdgcode = charge*GetSpeciesPdgCode((ESpecies)s);
           if(Pass(pdgcode)) continue; //check if we are intersted with particles of this type

           Double_t mass = pdgdb->GetParticle(pdgcode)->Mass();
           Double_t tEtot = TMath::Sqrt( mom[0]*mom[0] + mom[1]*mom[1] + mom[2]*mom[2] + mass*mass);//total energy of the track

           AliHBTParticle* track = new AliHBTParticle(pdgcode, w[s],i,
                                                      mom[0], mom[1], mom[2], tEtot,
                                                      pos[0], pos[1], pos[2], 0.);
           //copy probabilitis of other species (if not zero)
           for (Int_t k = 0; k<kNSpecies; k++)
            {
              if (k == s) continue;
              if (w[k] == 0.0) continue;
              track->SetPIDprobability(charge*GetSpeciesPdgCode( (ESpecies)k ),w[k]);
            }
           if(Pass(track))//check if meets all criteria of any of our cuts
                          //if it does not delete it and take next good track
            {
              delete track;
              continue;
            }

           fTracksEvent->AddParticle(track);
           if (particle) fParticlesEvent->AddParticle(particle);
           keeppart = kTRUE;

           if (AliHBTParticle::GetDebug() > 4 )
            {
              Info("ReadNext","\n\nAdding Particle with incarnation %d",pdgcode);
              track->Print();
            }
         }//for (Int_t s = 0; s<kNSpecies; s++)

        if (keeppart == kFALSE) delete particle;//particle was not stored in event

      }//for (Int_t i = 0;i<ntr; i++)  -- loop over tracks

     Info("ReadNext","Read %d tracks and %d particles from event %d (event %d in dir %d).",
            fTracksEvent->GetNumberOfParticles(), fParticlesEvent->GetNumberOfParticles(),
            fNEventsRead,fCurrentEvent,fCurrentDir);

     fCurrentEvent++;
     fNEventsRead++;
     delete esd;
     return 0;//success -> read one event
   }while(fCurrentDir < GetNumberOfDirs());//end of loop over directories specified in fDirs Obj Array

  return 1; //no more directories to read
}
/**********************************************************/
void AliHBTReaderESD::Rewind()
{
  //rewinds reading
  delete fFile;
  fFile = 0;
  delete fRunLoader;
  fCurrentDir = 0;
  fNEventsRead = 0;
  fCurrentEvent++;
}
/**********************************************************/

TFile* AliHBTReaderESD::OpenFile(Int_t n)
{
//opens fFile with kine tree

 const TString& dirname = GetDirName(n);
 if (dirname == "")
  {
   Error("OpenFiles","Can not get directory name");
   return 0x0;
  }
 TString filename = dirname +"/"+ fESDFileName;
 TFile *ret = TFile::Open(filename.Data());

 if ( ret == 0x0)
  {
    Error("OpenFiles","Can't open fFile %s",filename.Data());
    return 0x0;
  }
 if (!ret->IsOpen())
  {
    Error("OpenFiles","Can't open fFile  %s",filename.Data());
    return 0x0;
  }

 if (fReadParticles)
  {
   fRunLoader = AliRunLoader::Open(dirname +"/"+ fGAlFileName);
   if (fRunLoader == 0x0)
    {
      Error("OpenFiles","Can't get RunLoader for directory %s",dirname.Data());
      delete ret;
      return 0x0;
    }
   fRunLoader->LoadHeader();
   if (fRunLoader->LoadKinematics())
    {
      Error("Next","Error occured while loading kinematics.");
      delete fRunLoader;
      delete ret;
      return 0x0;
    }
  }
 return ret;
}
/**********************************************************/

Int_t AliHBTReaderESD::GetSpeciesPdgCode(ESpecies spec)//skowron
{
  //returns pdg code from the PID index
  //ask jura about charge
  switch (spec)
   {
     case kESDElectron:
       return kPositron;
       break;
     case kESDMuon:
       return kMuonPlus;
       break;
     case kESDPion:
       return kPiPlus;
       break;
     case kESDKaon:
       return kKPlus;
       break;
     case kESDProton:
       return kProton;
       break;
     default:
       ::Warning("GetSpeciesPdgCode","Specie with number %d is not defined.",(Int_t)spec);
       break;
   }
  return 0;
}
<|endoftext|>


<commit_before>//===-- BasicBlock.cpp - Implement BasicBlock related methods -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the BasicBlock class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/BasicBlock.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/LeakDetector.h"
#include "SymbolTableListTraitsImpl.h"
#include <algorithm>
using namespace llvm;

namespace {
  /// DummyInst - An instance of this class is used to mark the end of the
  /// instruction list.  This is not a real instruction.
  struct DummyInst : public Instruction {
    DummyInst() : Instruction(Type::VoidTy, OtherOpsEnd, 0, 0) {
      // This should not be garbage monitored.
      LeakDetector::removeGarbageObject(this);
    }

    virtual Instruction *clone() const {
      assert(0 && "Cannot clone EOL");abort();
      return 0;
    }
    virtual const char *getOpcodeName() const { return "*end-of-list-inst*"; }

    // Methods for support type inquiry through isa, cast, and dyn_cast...
    static inline bool classof(const DummyInst *) { return true; }
    static inline bool classof(const Instruction *I) {
      return I->getOpcode() == OtherOpsEnd;
    }
    static inline bool classof(const Value *V) {
      return isa<Instruction>(V) && classof(cast<Instruction>(V));
    }
  };
}

Instruction *ilist_traits<Instruction>::createSentinel() {
  return new DummyInst();
}
iplist<Instruction> &ilist_traits<Instruction>::getList(BasicBlock *BB) {
  return BB->getInstList();
}

// Explicit instantiation of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class SymbolTableListTraits<Instruction, BasicBlock, Function>;

BasicBlock::BasicBlock(const std::string &Name, Function *Parent,
                       BasicBlock *InsertBefore)
  : Value(Type::LabelTy, Value::BasicBlockVal, Name) {
  // Initialize the instlist...
  InstList.setItemParent(this);

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (InsertBefore) {
    assert(Parent &&
           "Cannot insert block before another block with no function!");
    Parent->getBasicBlockList().insert(InsertBefore, this);
  } else if (Parent) {
    Parent->getBasicBlockList().push_back(this);
  }
}

BasicBlock::~BasicBlock() {
  assert(getParent() == 0 && "BasicBlock still linked into the program!");
  dropAllReferences();
  InstList.clear();
}

void BasicBlock::setParent(Function *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);

  InstList.setParent(parent);

  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

void BasicBlock::removeFromParent() {
  getParent()->getBasicBlockList().remove(this);
}

void BasicBlock::eraseFromParent() {
  getParent()->getBasicBlockList().erase(this);
}

TerminatorInst *BasicBlock::getTerminator() {
  if (InstList.empty()) return 0;
  return dyn_cast<TerminatorInst>(&InstList.back());
}

const TerminatorInst *const BasicBlock::getTerminator() const {
  if (InstList.empty()) return 0;
  return dyn_cast<TerminatorInst>(&InstList.back());
}

void BasicBlock::dropAllReferences() {
  for(iterator I = begin(), E = end(); I != E; ++I)
    I->dropAllReferences();
}

/// getSinglePredecessor - If this basic block has a single predecessor block,
/// return the block, otherwise return a null pointer.
BasicBlock *BasicBlock::getSinglePredecessor() {
  pred_iterator PI = pred_begin(this), E = pred_end(this);
  if (PI == E) return 0;         // No preds.
  BasicBlock *ThePred = *PI;
  ++PI;
  return (PI == E) ? ThePred : 0 /*multiple preds*/;
}

/// removePredecessor - This method is used to notify a BasicBlock that the
/// specified Predecessor of the block is no longer able to reach it.  This is
/// actually not used to update the Predecessor list, but is actually used to
/// update the PHI nodes that reside in the block.  Note that this should be
/// called while the predecessor still refers to this block.
///
void BasicBlock::removePredecessor(BasicBlock *Pred,
                                   bool DontDeleteUselessPHIs) {
  assert((hasNUsesOrMore(16)||// Reduce cost of this assertion for complex CFGs.
          find(pred_begin(this), pred_end(this), Pred) != pred_end(this)) &&
         "removePredecessor: BB is not a predecessor!");

  if (InstList.empty()) return;
  PHINode *APN = dyn_cast<PHINode>(&front());
  if (!APN) return;   // Quick exit.

  // If there are exactly two predecessors, then we want to nuke the PHI nodes
  // altogether.  However, we cannot do this, if this in this case:
  //
  //  Loop:
  //    %x = phi [X, Loop]
  //    %x2 = add %x, 1         ;; This would become %x2 = add %x2, 1
  //    br Loop                 ;; %x2 does not dominate all uses
  //
  // This is because the PHI node input is actually taken from the predecessor
  // basic block.  The only case this can happen is with a self loop, so we
  // check for this case explicitly now.
  //
  unsigned max_idx = APN->getNumIncomingValues();
  assert(max_idx != 0 && "PHI Node in block with 0 predecessors!?!?!");
  if (max_idx == 2) {
    BasicBlock *Other = APN->getIncomingBlock(APN->getIncomingBlock(0) == Pred);

    // Disable PHI elimination!
    if (this == Other) max_idx = 3;
  }

  // <= Two predecessors BEFORE I remove one?
  if (max_idx <= 2 && !DontDeleteUselessPHIs) {
    // Yup, loop through and nuke the PHI nodes
    while (PHINode *PN = dyn_cast<PHINode>(&front())) {
      // Remove the predecessor first.
      PN->removeIncomingValue(Pred, !DontDeleteUselessPHIs);

      // If the PHI _HAD_ two uses, replace PHI node with its now *single* value
      if (max_idx == 2) {
        if (PN->getOperand(0) != PN)
          PN->replaceAllUsesWith(PN->getOperand(0));
        else
          // We are left with an infinite loop with no entries: kill the PHI.
          PN->replaceAllUsesWith(UndefValue::get(PN->getType()));
        getInstList().pop_front();    // Remove the PHI node
      }

      // If the PHI node already only had one entry, it got deleted by
      // removeIncomingValue.
    }
  } else {
    // Okay, now we know that we need to remove predecessor #pred_idx from all
    // PHI nodes.  Iterate over each PHI node fixing them up
    PHINode *PN;
    for (iterator II = begin(); (PN = dyn_cast<PHINode>(II)); ++II) {
      PN->removeIncomingValue(Pred, false);
      // If all incoming values to the Phi are the same, we can replace the Phi
      // with that value.
      if (Value *PNV = PN->hasConstantValue()) {
        PN->replaceAllUsesWith(PNV);
        PN->eraseFromParent();
      }
    }
  }
}

/// splitBasicBlock - This splits a basic block into two at the specified
/// instruction.  Note that all instructions BEFORE the specified iterator stay
/// as part of the original basic block, an unconditional branch is added to
/// the new BB, and the rest of the instructions in the BB are moved to the new
/// BB, including the old terminator.  This invalidates the iterator.
///
/// Note that this only works on well formed basic blocks (must have a
/// terminator), and 'I' must not be the end of instruction list (which would
/// cause a degenerate basic block to be formed, having a terminator inside of
/// the basic block).
///
BasicBlock *BasicBlock::splitBasicBlock(iterator I, const std::string &BBName) {
  assert(getTerminator() && "Can't use splitBasicBlock on degenerate BB!");
  assert(I != InstList.end() &&
         "Trying to get me to create degenerate basic block!");

  BasicBlock *New = new BasicBlock(BBName, getParent(), getNext());

  // Move all of the specified instructions from the original basic block into
  // the new basic block.
  New->getInstList().splice(New->end(), this->getInstList(), I, end());

  // Add a branch instruction to the newly formed basic block.
  new BranchInst(New, this);

  // Now we must loop through all of the successors of the New block (which
  // _were_ the successors of the 'this' block), and update any PHI nodes in
  // successors.  If there were PHI nodes in the successors, then they need to
  // know that incoming branches will be from New, not from Old.
  //
  for (succ_iterator I = succ_begin(New), E = succ_end(New); I != E; ++I) {
    // Loop over any phi nodes in the basic block, updating the BB field of
    // incoming values...
    BasicBlock *Successor = *I;
    PHINode *PN;
    for (BasicBlock::iterator II = Successor->begin();
         (PN = dyn_cast<PHINode>(II)); ++II) {
      int IDX = PN->getBasicBlockIndex(this);
      while (IDX != -1) {
        PN->setIncomingBlock((unsigned)IDX, New);
        IDX = PN->getBasicBlockIndex(this);
      }
    }
  }
  return New;
}
<commit_msg>Fix an iterator invalidation problem when we decide a phi has a constant value<commit_after>//===-- BasicBlock.cpp - Implement BasicBlock related methods -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the BasicBlock class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/BasicBlock.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/LeakDetector.h"
#include "SymbolTableListTraitsImpl.h"
#include <algorithm>
using namespace llvm;

namespace {
  /// DummyInst - An instance of this class is used to mark the end of the
  /// instruction list.  This is not a real instruction.
  struct DummyInst : public Instruction {
    DummyInst() : Instruction(Type::VoidTy, OtherOpsEnd, 0, 0) {
      // This should not be garbage monitored.
      LeakDetector::removeGarbageObject(this);
    }

    virtual Instruction *clone() const {
      assert(0 && "Cannot clone EOL");abort();
      return 0;
    }
    virtual const char *getOpcodeName() const { return "*end-of-list-inst*"; }

    // Methods for support type inquiry through isa, cast, and dyn_cast...
    static inline bool classof(const DummyInst *) { return true; }
    static inline bool classof(const Instruction *I) {
      return I->getOpcode() == OtherOpsEnd;
    }
    static inline bool classof(const Value *V) {
      return isa<Instruction>(V) && classof(cast<Instruction>(V));
    }
  };
}

Instruction *ilist_traits<Instruction>::createSentinel() {
  return new DummyInst();
}
iplist<Instruction> &ilist_traits<Instruction>::getList(BasicBlock *BB) {
  return BB->getInstList();
}

// Explicit instantiation of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class SymbolTableListTraits<Instruction, BasicBlock, Function>;

BasicBlock::BasicBlock(const std::string &Name, Function *Parent,
                       BasicBlock *InsertBefore)
  : Value(Type::LabelTy, Value::BasicBlockVal, Name) {
  // Initialize the instlist...
  InstList.setItemParent(this);

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (InsertBefore) {
    assert(Parent &&
           "Cannot insert block before another block with no function!");
    Parent->getBasicBlockList().insert(InsertBefore, this);
  } else if (Parent) {
    Parent->getBasicBlockList().push_back(this);
  }
}

BasicBlock::~BasicBlock() {
  assert(getParent() == 0 && "BasicBlock still linked into the program!");
  dropAllReferences();
  InstList.clear();
}

void BasicBlock::setParent(Function *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);

  InstList.setParent(parent);

  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

void BasicBlock::removeFromParent() {
  getParent()->getBasicBlockList().remove(this);
}

void BasicBlock::eraseFromParent() {
  getParent()->getBasicBlockList().erase(this);
}

TerminatorInst *BasicBlock::getTerminator() {
  if (InstList.empty()) return 0;
  return dyn_cast<TerminatorInst>(&InstList.back());
}

const TerminatorInst *const BasicBlock::getTerminator() const {
  if (InstList.empty()) return 0;
  return dyn_cast<TerminatorInst>(&InstList.back());
}

void BasicBlock::dropAllReferences() {
  for(iterator I = begin(), E = end(); I != E; ++I)
    I->dropAllReferences();
}

/// getSinglePredecessor - If this basic block has a single predecessor block,
/// return the block, otherwise return a null pointer.
BasicBlock *BasicBlock::getSinglePredecessor() {
  pred_iterator PI = pred_begin(this), E = pred_end(this);
  if (PI == E) return 0;         // No preds.
  BasicBlock *ThePred = *PI;
  ++PI;
  return (PI == E) ? ThePred : 0 /*multiple preds*/;
}

/// removePredecessor - This method is used to notify a BasicBlock that the
/// specified Predecessor of the block is no longer able to reach it.  This is
/// actually not used to update the Predecessor list, but is actually used to
/// update the PHI nodes that reside in the block.  Note that this should be
/// called while the predecessor still refers to this block.
///
void BasicBlock::removePredecessor(BasicBlock *Pred,
                                   bool DontDeleteUselessPHIs) {
  assert((hasNUsesOrMore(16)||// Reduce cost of this assertion for complex CFGs.
          find(pred_begin(this), pred_end(this), Pred) != pred_end(this)) &&
         "removePredecessor: BB is not a predecessor!");

  if (InstList.empty()) return;
  PHINode *APN = dyn_cast<PHINode>(&front());
  if (!APN) return;   // Quick exit.

  // If there are exactly two predecessors, then we want to nuke the PHI nodes
  // altogether.  However, we cannot do this, if this in this case:
  //
  //  Loop:
  //    %x = phi [X, Loop]
  //    %x2 = add %x, 1         ;; This would become %x2 = add %x2, 1
  //    br Loop                 ;; %x2 does not dominate all uses
  //
  // This is because the PHI node input is actually taken from the predecessor
  // basic block.  The only case this can happen is with a self loop, so we
  // check for this case explicitly now.
  //
  unsigned max_idx = APN->getNumIncomingValues();
  assert(max_idx != 0 && "PHI Node in block with 0 predecessors!?!?!");
  if (max_idx == 2) {
    BasicBlock *Other = APN->getIncomingBlock(APN->getIncomingBlock(0) == Pred);

    // Disable PHI elimination!
    if (this == Other) max_idx = 3;
  }

  // <= Two predecessors BEFORE I remove one?
  if (max_idx <= 2 && !DontDeleteUselessPHIs) {
    // Yup, loop through and nuke the PHI nodes
    while (PHINode *PN = dyn_cast<PHINode>(&front())) {
      // Remove the predecessor first.
      PN->removeIncomingValue(Pred, !DontDeleteUselessPHIs);

      // If the PHI _HAD_ two uses, replace PHI node with its now *single* value
      if (max_idx == 2) {
        if (PN->getOperand(0) != PN)
          PN->replaceAllUsesWith(PN->getOperand(0));
        else
          // We are left with an infinite loop with no entries: kill the PHI.
          PN->replaceAllUsesWith(UndefValue::get(PN->getType()));
        getInstList().pop_front();    // Remove the PHI node
      }

      // If the PHI node already only had one entry, it got deleted by
      // removeIncomingValue.
    }
  } else {
    // Okay, now we know that we need to remove predecessor #pred_idx from all
    // PHI nodes.  Iterate over each PHI node fixing them up
    PHINode *PN;
    for (iterator II = begin(); (PN = dyn_cast<PHINode>(II)); ) {
      ++II;
      PN->removeIncomingValue(Pred, false);
      // If all incoming values to the Phi are the same, we can replace the Phi
      // with that value.
      if (Value *PNV = PN->hasConstantValue()) {
        PN->replaceAllUsesWith(PNV);
        PN->eraseFromParent();
      }
    }
  }
}

/// splitBasicBlock - This splits a basic block into two at the specified
/// instruction.  Note that all instructions BEFORE the specified iterator stay
/// as part of the original basic block, an unconditional branch is added to
/// the new BB, and the rest of the instructions in the BB are moved to the new
/// BB, including the old terminator.  This invalidates the iterator.
///
/// Note that this only works on well formed basic blocks (must have a
/// terminator), and 'I' must not be the end of instruction list (which would
/// cause a degenerate basic block to be formed, having a terminator inside of
/// the basic block).
///
BasicBlock *BasicBlock::splitBasicBlock(iterator I, const std::string &BBName) {
  assert(getTerminator() && "Can't use splitBasicBlock on degenerate BB!");
  assert(I != InstList.end() &&
         "Trying to get me to create degenerate basic block!");

  BasicBlock *New = new BasicBlock(BBName, getParent(), getNext());

  // Move all of the specified instructions from the original basic block into
  // the new basic block.
  New->getInstList().splice(New->end(), this->getInstList(), I, end());

  // Add a branch instruction to the newly formed basic block.
  new BranchInst(New, this);

  // Now we must loop through all of the successors of the New block (which
  // _were_ the successors of the 'this' block), and update any PHI nodes in
  // successors.  If there were PHI nodes in the successors, then they need to
  // know that incoming branches will be from New, not from Old.
  //
  for (succ_iterator I = succ_begin(New), E = succ_end(New); I != E; ++I) {
    // Loop over any phi nodes in the basic block, updating the BB field of
    // incoming values...
    BasicBlock *Successor = *I;
    PHINode *PN;
    for (BasicBlock::iterator II = Successor->begin();
         (PN = dyn_cast<PHINode>(II)); ++II) {
      int IDX = PN->getBasicBlockIndex(this);
      while (IDX != -1) {
        PN->setIncomingBlock((unsigned)IDX, New);
        IDX = PN->getBasicBlockIndex(this);
      }
    }
  }
  return New;
}
<|endoftext|>


<commit_before>#include "soundeffect.h"

#include <AL/al.h>
#include <AL/alc.h>

#include <Tempest/SoundDevice>
#include <Tempest/Except>
#include <Tempest/Log>

#include <thread>
#include <atomic>

using namespace Tempest;

struct SoundEffect::Impl {
  enum {
    NUM_BUF = 3,
    BUFSZ   = 4096
    };

  Impl()=default;

  Impl(SoundDevice &dev, const Sound &src)
    :dev(&dev), data(src.data) {
    if(data==nullptr)
      return;
    ALCcontext* ctx = context();
    alGenSourcesCt(ctx, 1, &source);
    alSourceBufferCt(ctx, source, reinterpret_cast<ALbuffer*>(data->buffer));
    }

  Impl(SoundDevice &dev, std::unique_ptr<SoundProducer> &&src)
    :dev(&dev), data(nullptr), producer(std::move(src)) {
    ALCcontext* ctx = context();
    alGenSourcesCt(ctx, 1, &source);

    threadFlag.store(true);
    producerThread = std::thread([this](){
      soundThreadFn();
      });
    }

  ~Impl(){
    if(source==0)
      return;

    ALCcontext* ctx = context();
    if(threadFlag.load()) {
      threadFlag.store(false);
      producerThread.join();
      producer.reset();
      } else {
      alDeleteSourcesCt(ctx, 1, &source);
      }
    }

  void soundThreadFn() {
    SoundProducer& src  = *producer;
    ALsizei        freq = src.frequency;
    ALenum         frm  = src.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
    auto           ctx  = context();
    ALbuffer*      qBuffer[NUM_BUF]={};
    int16_t        bufData[BUFSZ*2]={};
    ALint          state=AL_INITIAL;
    ALint          zero=0;

    for(size_t i=0;i<NUM_BUF;++i){
      auto b = alNewBuffer();
      if(b==nullptr){
        for(size_t r=0;r<i;++r)
          alDelBuffer(b);
        return;
        }
      qBuffer[i] = b;
      }

    for(int i=0;i<NUM_BUF;++i) {
      renderSound(src,bufData,BUFSZ);
      alBufferDataCt(ctx, qBuffer[i], frm, bufData, BUFSZ*sizeof(int16_t)*2, freq);
      }
    alSourceQueueBuffersCt(ctx,source,NUM_BUF,qBuffer);
    alSourceivCt(ctx,source,AL_LOOPING,&zero);
    alSourcePlayvCt(ctx,1,&source);

    while(threadFlag.load()) {
      int bufInQueue=0, bufProcessed=0;
      alGetSourceivCt(ctx,source, AL_BUFFERS_QUEUED,    &bufInQueue);
      alGetSourceivCt(ctx,source, AL_BUFFERS_PROCESSED, &bufProcessed);

      if(bufInQueue>2 && bufProcessed==0){
        std::this_thread::yield();
        continue;
        }

      for(int i=0;i<bufProcessed;++i) {
        ALbuffer* nextBuffer=nullptr;
        alSourceUnqueueBuffersCt(ctx,source,1,&nextBuffer);

        renderSound(src,bufData,BUFSZ);
        alBufferDataCt(ctx, nextBuffer, frm, bufData, BUFSZ*sizeof(int16_t)*2, freq);
        alSourceQueueBuffersCt(ctx,source,1,&nextBuffer);
        }

      alGetSourceivCt(ctx,source, AL_BUFFERS_QUEUED, &bufInQueue);
      if(bufInQueue==1){
        uint64_t t = (uint64_t(1000u)*BUFSZ)/uint64_t(freq);
        std::this_thread::sleep_for(std::chrono::milliseconds(t));
        }

      alGetSourceivCt(ctx,source,AL_SOURCE_STATE,&state);
      if(state==AL_STOPPED)
        alSourcePlayvCt(ctx,1,&source); //HACK
      }

    alSourcePausevCt(ctx,1,&source);
    alDeleteSourcesCt(ctx, 1, &source);
    for(size_t i=0;i<NUM_BUF;++i)
      alDelBuffer(qBuffer[i]);
    source=0;
    }

  void renderSound(SoundProducer& src,int16_t* data,size_t sz) noexcept {
    src.renderSound(data,sz);
    }

  ALCcontext* context(){
    return reinterpret_cast<ALCcontext*>(dev->context());
    }

  SoundDevice*                   dev    = nullptr;
  std::shared_ptr<Sound::Data>   data;
  uint32_t                       source = 0;

  std::thread                    producerThread;
  std::atomic_bool               threadFlag={false};
  std::unique_ptr<SoundProducer> producer;
  };

SoundProducer::SoundProducer(uint16_t frequency, uint16_t channels)
  :frequency(frequency),channels(channels){
  if(channels!=1 && channels!=2)
    throw std::system_error(Tempest::SoundErrc::InvalidChannelsCount);
  }

SoundEffect::SoundEffect(SoundDevice &dev, const Sound &src)
  :impl(new Impl(dev,src)) {
  }

SoundEffect::SoundEffect(SoundDevice &dev, std::unique_ptr<SoundProducer> &&src)
  :impl(new Impl(dev,std::move(src))) {
  }

SoundEffect::SoundEffect()
  :impl(new Impl()){
  }

SoundEffect::SoundEffect(Tempest::SoundEffect &&s)
  :impl(std::move(s.impl)) {
  }

SoundEffect::~SoundEffect() {
  }

SoundEffect &SoundEffect::operator=(Tempest::SoundEffect &&s){
  std::swap(impl,s.impl);
  return *this;
  }

void SoundEffect::play() {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcePlayvCt(ctx,1,&impl->source);
  }

void SoundEffect::pause() {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcePausevCt(ctx,1,&impl->source);
  }

bool SoundEffect::isEmpty() const {
  return impl->source==0;
  }

bool SoundEffect::isFinished() const {
  if(impl->source==0)
    return true;
  int32_t state=0;
  ALCcontext* ctx = impl->context();
  alGetSourceivCt(ctx,impl->source,AL_SOURCE_STATE,&state);
  return state==AL_STOPPED || state==AL_INITIAL;
  }

uint64_t Tempest::SoundEffect::timeLength() const {
  if(impl->data)
    return impl->data->timeLength();
  return 0;
  }

uint64_t Tempest::SoundEffect::currentTime() const {
  if(impl->source==0)
    return 0;
  float result=0;
  ALCcontext* ctx = impl->context();
  alGetSourcefvCt(ctx, impl->source, AL_SEC_OFFSET, &result);
  return uint64_t(result*1000);
  }

void SoundEffect::setPosition(float x, float y, float z) {
  float p[3]={x,y,z};
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_POSITION, p);
  }

std::array<float,3> SoundEffect::position() const {
  std::array<float,3> ret={};
  if(impl->source==0)
    return ret;
  ALCcontext* ctx = impl->context();
  alGetSourcefvCt(ctx,impl->source,AL_POSITION,&ret[0]);
  return ret;
  }

float SoundEffect::x() const {
  return position()[0];
  }

float SoundEffect::y() const {
  return position()[1];
  }

float SoundEffect::z() const {
  return position()[2];
  }

void SoundEffect::setMaxDistance(float dist) {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_MAX_DISTANCE, &dist);
  }

void SoundEffect::setRefDistance(float dist) {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_REFERENCE_DISTANCE, &dist);
  }

void SoundEffect::setVolume(float val) {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_GAIN, &val);
  }

float SoundEffect::volume() const {
  if(impl->source==0)
    return 0;
  float val=0;
  ALCcontext* ctx = impl->context();
  alGetSourcefvCt(ctx, impl->source, AL_GAIN, &val);
  return val;
  }
<commit_msg>Update soundeffect.cpp<commit_after>#include "soundeffect.h"

#include <AL/al.h>
#include <AL/alc.h>

#include <Tempest/SoundDevice>
#include <Tempest/Except>
#include <Tempest/Log>

#include <thread>
#include <atomic>

using namespace Tempest;

struct SoundEffect::Impl {
  enum {
    NUM_BUF = 3,
    BUFSZ   = 4096
    };

  Impl()=default;

  Impl(SoundDevice &dev, const Sound &src)
    :dev(&dev), data(src.data) {
    if(data==nullptr)
      return;
    ALCcontext* ctx = context();
    alGenSourcesCt(ctx, 1, &source);
    alSourceBufferCt(ctx, source, reinterpret_cast<ALbuffer*>(data->buffer));
    }

  Impl(SoundDevice &dev, std::unique_ptr<SoundProducer> &&src)
    :dev(&dev), data(nullptr), producer(std::move(src)) {
    ALCcontext* ctx = context();
    alGenSourcesCt(ctx, 1, &source);

    threadFlag.store(true);
    producerThread = std::thread([this](){
      soundThreadFn();
      });
    }

  ~Impl(){
    if(source==0)
      return;

    ALCcontext* ctx = context();
    if(threadFlag.load()) {
      threadFlag.store(false);
      producerThread.join();
      producer.reset();
      } else {
      alDeleteSourcesCt(ctx, 1, &source);
      }
    }

  void soundThreadFn() {
    SoundProducer& src  = *producer;
    ALsizei        freq = src.frequency;
    ALenum         frm  = src.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
    auto           ctx  = context();
    ALbuffer*      qBuffer[NUM_BUF]={};
    int16_t        bufData[BUFSZ*2]={};
    ALint          state=AL_INITIAL;
    ALint          zero=0;

    for(size_t i=0;i<NUM_BUF;++i){
      auto b = alNewBuffer();
      if(b==nullptr){
        for(size_t r=0;r<i;++r)
          alDelBuffer(b);
        return;
        }
      qBuffer[i] = b;
      }

    for(int i=0;i<NUM_BUF;++i) {
      renderSound(src,bufData,BUFSZ);
      alBufferDataCt(ctx, qBuffer[i], frm, bufData, BUFSZ*sizeof(int16_t)*2, freq);
      }
    alSourceQueueBuffersCt(ctx,source,NUM_BUF,qBuffer);
    alSourceivCt(ctx,source,AL_LOOPING,&zero);
    alSourcePlayvCt(ctx,1,&source);

    while(threadFlag.load()) {
      int bufInQueue=0, bufProcessed=0;
      alGetSourceivCt(ctx,source, AL_BUFFERS_QUEUED,    &bufInQueue);
      alGetSourceivCt(ctx,source, AL_BUFFERS_PROCESSED, &bufProcessed);

      if(bufInQueue>2 && bufProcessed==0){
        std::this_thread::yield();
        continue;
        }

      int bufC = (bufInQueue-bufProcessed);
      for(int i=bufC;i<NUM_BUF;++i) {
        ALbuffer* nextBuffer=nullptr;
        alSourceUnqueueBuffersCt(ctx,source,1,&nextBuffer);

        renderSound(src,bufData,BUFSZ);
        alBufferDataCt(ctx, nextBuffer, frm, bufData, BUFSZ*sizeof(int16_t)*2, freq);
        alSourceQueueBuffersCt(ctx,source,1,&nextBuffer);
        }

      alGetSourceivCt(ctx,source, AL_BUFFERS_QUEUED,    &bufInQueue);
      alGetSourceivCt(ctx,source, AL_BUFFERS_PROCESSED, &bufProcessed);
      bufC = (bufInQueue-bufProcessed);
      if(bufC>2){
        uint64_t t = (uint64_t(1000u)*BUFSZ)/uint64_t(freq);
        std::this_thread::sleep_for(std::chrono::milliseconds(t));
        }

      alGetSourceivCt(ctx,source,AL_SOURCE_STATE,&state);
      if(state==AL_STOPPED)
        alSourcePlayvCt(ctx,1,&source); //HACK
      }

    alSourcePausevCt(ctx,1,&source);
    alDeleteSourcesCt(ctx, 1, &source);
    for(size_t i=0;i<NUM_BUF;++i)
      alDelBuffer(qBuffer[i]);
    source=0;
    }

  void renderSound(SoundProducer& src,int16_t* data,size_t sz) noexcept {
    src.renderSound(data,sz);
    }

  ALCcontext* context(){
    return reinterpret_cast<ALCcontext*>(dev->context());
    }

  SoundDevice*                   dev    = nullptr;
  std::shared_ptr<Sound::Data>   data;
  uint32_t                       source = 0;

  std::thread                    producerThread;
  std::atomic_bool               threadFlag={false};
  std::unique_ptr<SoundProducer> producer;
  };

SoundProducer::SoundProducer(uint16_t frequency, uint16_t channels)
  :frequency(frequency),channels(channels){
  if(channels!=1 && channels!=2)
    throw std::system_error(Tempest::SoundErrc::InvalidChannelsCount);
  }

SoundEffect::SoundEffect(SoundDevice &dev, const Sound &src)
  :impl(new Impl(dev,src)) {
  }

SoundEffect::SoundEffect(SoundDevice &dev, std::unique_ptr<SoundProducer> &&src)
  :impl(new Impl(dev,std::move(src))) {
  }

SoundEffect::SoundEffect()
  :impl(new Impl()){
  }

SoundEffect::SoundEffect(Tempest::SoundEffect &&s)
  :impl(std::move(s.impl)) {
  }

SoundEffect::~SoundEffect() {
  }

SoundEffect &SoundEffect::operator=(Tempest::SoundEffect &&s){
  std::swap(impl,s.impl);
  return *this;
  }

void SoundEffect::play() {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcePlayvCt(ctx,1,&impl->source);
  }

void SoundEffect::pause() {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcePausevCt(ctx,1,&impl->source);
  }

bool SoundEffect::isEmpty() const {
  return impl->source==0;
  }

bool SoundEffect::isFinished() const {
  if(impl->source==0)
    return true;
  int32_t state=0;
  ALCcontext* ctx = impl->context();
  alGetSourceivCt(ctx,impl->source,AL_SOURCE_STATE,&state);
  return state==AL_STOPPED || state==AL_INITIAL;
  }

uint64_t Tempest::SoundEffect::timeLength() const {
  if(impl->data)
    return impl->data->timeLength();
  return 0;
  }

uint64_t Tempest::SoundEffect::currentTime() const {
  if(impl->source==0)
    return 0;
  float result=0;
  ALCcontext* ctx = impl->context();
  alGetSourcefvCt(ctx, impl->source, AL_SEC_OFFSET, &result);
  return uint64_t(result*1000);
  }

void SoundEffect::setPosition(float x, float y, float z) {
  float p[3]={x,y,z};
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_POSITION, p);
  }

std::array<float,3> SoundEffect::position() const {
  std::array<float,3> ret={};
  if(impl->source==0)
    return ret;
  ALCcontext* ctx = impl->context();
  alGetSourcefvCt(ctx,impl->source,AL_POSITION,&ret[0]);
  return ret;
  }

float SoundEffect::x() const {
  return position()[0];
  }

float SoundEffect::y() const {
  return position()[1];
  }

float SoundEffect::z() const {
  return position()[2];
  }

void SoundEffect::setMaxDistance(float dist) {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_MAX_DISTANCE, &dist);
  }

void SoundEffect::setRefDistance(float dist) {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_REFERENCE_DISTANCE, &dist);
  }

void SoundEffect::setVolume(float val) {
  if(impl->source==0)
    return;
  ALCcontext* ctx = impl->context();
  alSourcefvCt(ctx, impl->source, AL_GAIN, &val);
  }

float SoundEffect::volume() const {
  if(impl->source==0)
    return 0;
  float val=0;
  ALCcontext* ctx = impl->context();
  alGetSourcefvCt(ctx, impl->source, AL_GAIN, &val);
  return val;
  }
<|endoftext|>


<commit_before>#include "x11api.h"

#ifdef __LINUX__
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <X11/keysymdef.h>
#include <X11/Xutil.h>
//#include <GL/glx.h> //FIXME

#include <Tempest/Event>
#include <Tempest/TextCodec>
#include <Tempest/Window>

#include <atomic>
#include <stdexcept>
#include <cstring>
#include <thread>
#include <unordered_map>

struct HWND final {
  ::Window wnd;
  HWND()=default;
  HWND(::Window w):wnd(w) {
    }
  HWND(Tempest::SystemApi::Window* p) {
    std::memcpy(&wnd,&p,sizeof(wnd));
    }

  HWND& operator = (::Window w) { wnd = w; return *this; }

  operator ::Window() { return wnd; }

  Tempest::SystemApi::Window* ptr() {
    static_assert (sizeof(::Window)<=sizeof(void*),"cannot map X11 window handle to pointer");
    Tempest::SystemApi::Window* ret=nullptr;
    std::memcpy(&ret,&wnd,sizeof(wnd));
    return ret;
    }
  };

using namespace Tempest;

static const char*      wndClassName="Tempest.Window";
static Display*         dpy  = nullptr;
static ::Window         root = {};
static std::atomic_bool isExit{0};

static std::unordered_map<SystemApi::Window*,Tempest::Window*> windows;

static Atom& wmDeleteMessage(){
  static Atom w  = XInternAtom( dpy, "WM_DELETE_WINDOW", 0);
  return w;
  }

static Atom& _NET_WM_STATE(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE", 0);
  return w;
  }

static Atom& _NET_WM_STATE_MAXIMIZED_HORZ(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
  return w;
  }

static Atom& _NET_WM_STATE_MAXIMIZED_VERT(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
  return w;
  }

static Atom& _NET_WM_STATE_FULLSCREEN(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE_FULLSCREEN", 0);
  return w;
  }

static Event::MouseButton toButton( XButtonEvent& msg ){
  if( msg.button==Button1 )
    return Event::ButtonLeft;

  if( msg.button==Button3 )
    return Event::ButtonRight;

  if( msg.button==Button2 )
    return Event::ButtonMid;

  return Event::ButtonNone;
  }

static void maximizeWindow(HWND& w) {
  Atom a[2];
  a[0] = _NET_WM_STATE_MAXIMIZED_HORZ();
  a[1] = _NET_WM_STATE_MAXIMIZED_VERT();

  XChangeProperty ( dpy, w, _NET_WM_STATE(),
    XA_ATOM, 32, PropModeReplace, (unsigned char*)a, 2);
  XSync(dpy,False);
  }

X11Api::X11Api() {
  dpy = XOpenDisplay(nullptr);

  if(dpy == nullptr)
    throw std::runtime_error("cannot connect to X server!");

  root = DefaultRootWindow(dpy);

  static const TranslateKeyPair k[] = {
    { XK_KP_Left,   Event::K_Left     },
    { XK_KP_Right,  Event::K_Right    },
    { XK_KP_Up,     Event::K_Up       },
    { XK_KP_Down,   Event::K_Down     },

    { XK_Shift_L,   Event::K_LShift   },
    { XK_Shift_R,   Event::K_RShift   },

    { XK_Control_L, Event::K_LControl },
    { XK_Control_R, Event::K_RControl },

    { XK_Escape,    Event::K_ESCAPE   },
    { XK_Tab,       Event::K_Tab      },
    { XK_BackSpace, Event::K_Back     },
    { XK_Delete,    Event::K_Delete   },
    { XK_Insert,    Event::K_Insert   },
    { XK_Home,      Event::K_Home     },
    { XK_End,       Event::K_End      },
    { XK_Pause,     Event::K_Pause    },
    { XK_Return,    Event::K_Return   },

    { XK_F1,        Event::K_F1       },
    {   48,         Event::K_0        },
    {   97,         Event::K_A        },

    { 0,            Event::K_NoKey    }
    };

  setupKeyTranslate(k,24);
  }

void *X11Api::display() {
  return dpy;
  }

void X11Api::alignGeometry(SystemApi::Window *w, Tempest::Window& owner) {
  XWindowAttributes xwa={};
  if(XGetWindowAttributes(dpy, HWND(w), &xwa)){
    Tempest::SizeEvent e(xwa.width, xwa.height);
    SystemApi::dispatchResize(owner,e);
    }
  }

SystemApi::Window *X11Api::implCreateWindow(Tempest::Window *owner, uint32_t w, uint32_t h) {
  //GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  //XVisualInfo * vi = glXChooseVisual(dpy, 0, att);

  long visualMask = VisualScreenMask;
  int numberOfVisuals;
  XVisualInfo vInfoTemplate = {};
  vInfoTemplate.screen = DefaultScreen(dpy);
  XVisualInfo * vi = XGetVisualInfo(dpy, visualMask, &vInfoTemplate, &numberOfVisuals);

  Colormap cmap;
  cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);

  XSetWindowAttributes swa={};
  swa.colormap   = cmap;
  swa.event_mask = PointerMotionMask | ExposureMask |
                   ButtonPressMask | ButtonReleaseMask |
                   KeyPressMask | KeyReleaseMask;

  HWND win = XCreateWindow( dpy, root, 0, 0, w, h,
                            0, vi->depth, InputOutput, vi->visual,
                            CWColormap | CWEventMask, &swa );
  XSetWMProtocols(dpy, win, &wmDeleteMessage(), 1);
  XStoreName(dpy, win, wndClassName);

  XFreeColormap( dpy, cmap );
  XFree(vi);

  auto ret = reinterpret_cast<SystemApi::Window*>(win.ptr());
  windows[ret] = owner;
  //maximizeWindow(win);
  XMapWindow(dpy, win);
  XSync(dpy,False);
  alignGeometry(win.ptr(),*owner);
  return ret;
  }

SystemApi::Window *X11Api::implCreateWindow(Tempest::Window *owner, SystemApi::ShowMode sm) {
  return implCreateWindow(owner,800,600); //TODO
  }

void X11Api::implDestroyWindow(SystemApi::Window *w) {
  windows.erase(w);
  XDestroyWindow(dpy, HWND(w));
  }

bool X11Api::implSetAsFullscreen(SystemApi::Window *w, bool fullScreen) {
  return false;
  }

bool X11Api::implIsFullscreen(SystemApi::Window *w) {
  return false;
  }

void X11Api::implSetCursorPosition(int x, int y) {
  // TODO
  }

void X11Api::implShowCursor(bool show) {
  // TODO
  }

Rect X11Api::implWindowClientRect(SystemApi::Window *w) {
  XWindowAttributes xwa;
  XGetWindowAttributes(dpy, HWND(w), &xwa);

  return Rect( xwa.x, xwa.y, xwa.width, xwa.height );
  }

void X11Api::implExit() {
  isExit.store(true);
  }

bool X11Api::implIsRunning() {
  return !isExit.load();
  }

int X11Api::implExec(SystemApi::AppCallBack &cb) {
  // main message loop
  while (!isExit.load()) {
    implProcessEvents(cb);
    }
  return 0;
  }

void X11Api::implProcessEvents(SystemApi::AppCallBack &cb) {
  // main message loop
  if(XPending(dpy)>0) {
    XEvent xev={};
    XNextEvent(dpy, &xev);

    HWND hWnd = xev.xclient.window;
    Tempest::Window* cb = windows.find(hWnd.ptr())->second; //TODO: validation
    switch( xev.type ) {
      case ClientMessage: {
        if( xev.xclient.data.l[0] == long(wmDeleteMessage()) ){
          SystemApi::exit();
          }
        break;
        }
      case ButtonPress:
      case ButtonRelease: {
        if(cb) {
          bool isWheel = false;
          if( xev.type==ButtonPress && XPending(dpy) &&
              (xev.xbutton.button == Button4 || xev.xbutton.button == Button5) ){
            XEvent ev;
            XNextEvent(dpy, &ev);
            isWheel = (ev.type==ButtonRelease);
            }

          if( isWheel ){
            int ticks = 0;
            if( xev.xbutton.button == Button4 ) {
              ticks = 100;
              }
            else if ( xev.xbutton.button == Button5 ) {
              ticks = -100;
              }
            Tempest::MouseEvent e( xev.xbutton.x,
                                   xev.xbutton.y,
                                   Tempest::Event::ButtonNone,
                                   ticks,
                                   0,
                                   Event::MouseWheel );
            SystemApi::dispatchMouseWheel(*cb, e);
            } else {
            MouseEvent e( xev.xbutton.x,
                          xev.xbutton.y,
                          toButton( xev.xbutton ),
                          0,
                          0,
                          xev.type==ButtonPress ? Event::MouseDown : Event::MouseUp );
            if(xev.type==ButtonPress)
              SystemApi::dispatchMouseDown(*cb, e); else
              SystemApi::dispatchMouseUp(*cb, e);
            }
          }
        break;
        }
      case MotionNotify: {
        MouseEvent e( xev.xmotion.x,
                      xev.xmotion.y,
                      Event::ButtonNone,
                      0,
                      0,
                      Event::MouseMove  );
        SystemApi::dispatchMouseMove(*cb, e);
        break;
        }
      case KeyPress:
      case KeyRelease: {
        if(cb) {
          int keysyms_per_keycode_return = 0;
          KeySym *ksym = XGetKeyboardMapping( dpy, KeyCode(xev.xkey.keycode),
                                              1,
                                              &keysyms_per_keycode_return );

          char txt[10]={};
          XLookupString(&xev.xkey, txt, sizeof(txt)-1, ksym, nullptr );

          auto u16 = TextCodec::toUtf16(txt); // TODO: remove dynamic allocation
          auto key = SystemApi::translateKey(*ksym);

          uint32_t scan = xev.xkey.keycode;

          Tempest::KeyEvent e(Event::KeyType(key),uint32_t(u16.size()>0 ? u16[0] : 0),Event::M_NoModifier,(xev.type==KeyPress) ? Event::KeyDown : Event::KeyUp);
          if(xev.type==KeyPress)
            SystemApi::dispatchKeyDown(*cb,e,scan); else
            SystemApi::dispatchKeyUp  (*cb,e,scan);
            }
        break;
        }
      }

    std::this_thread::yield();
    } else {
    if(cb.onTimer()==0)
      std::this_thread::yield();
    for(auto& i:windows) {
      // artificial move/resize event
      alignGeometry(i.first,*i.second);
      SystemApi::dispatchRender(*i.second);
      }
    }
  }

#endif
<commit_msg>Fix linux crash<commit_after>#include "x11api.h"

#ifdef __LINUX__
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <X11/keysymdef.h>
#include <X11/Xutil.h>
//#include <GL/glx.h> //FIXME

#include <Tempest/Event>
#include <Tempest/TextCodec>
#include <Tempest/Window>

#include <atomic>
#include <stdexcept>
#include <cstring>
#include <thread>
#include <unordered_map>

struct HWND final {
  ::Window wnd;
  HWND()=default;
  HWND(::Window w):wnd(w) {
    }
  HWND(Tempest::SystemApi::Window* p) {
    std::memcpy(&wnd,&p,sizeof(wnd));
    }

  HWND& operator = (::Window w) { wnd = w; return *this; }

  operator ::Window() { return wnd; }

  Tempest::SystemApi::Window* ptr() {
    static_assert (sizeof(::Window)<=sizeof(void*),"cannot map X11 window handle to pointer");
    Tempest::SystemApi::Window* ret=nullptr;
    std::memcpy(&ret,&wnd,sizeof(wnd));
    return ret;
    }
  };

using namespace Tempest;

static const char*      wndClassName="Tempest.Window";
static Display*         dpy  = nullptr;
static ::Window         root = {};
static std::atomic_bool isExit{0};

static std::unordered_map<SystemApi::Window*,Tempest::Window*> windows;

static Atom& wmDeleteMessage(){
  static Atom w  = XInternAtom( dpy, "WM_DELETE_WINDOW", 0);
  return w;
  }

static Atom& _NET_WM_STATE(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE", 0);
  return w;
  }

static Atom& _NET_WM_STATE_MAXIMIZED_HORZ(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
  return w;
  }

static Atom& _NET_WM_STATE_MAXIMIZED_VERT(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
  return w;
  }

static Atom& _NET_WM_STATE_FULLSCREEN(){
  static Atom w  = XInternAtom( dpy, "_NET_WM_STATE_FULLSCREEN", 0);
  return w;
  }

static Event::MouseButton toButton( XButtonEvent& msg ){
  if( msg.button==Button1 )
    return Event::ButtonLeft;

  if( msg.button==Button3 )
    return Event::ButtonRight;

  if( msg.button==Button2 )
    return Event::ButtonMid;

  return Event::ButtonNone;
  }

static void maximizeWindow(HWND& w) {
  Atom a[2];
  a[0] = _NET_WM_STATE_MAXIMIZED_HORZ();
  a[1] = _NET_WM_STATE_MAXIMIZED_VERT();

  XChangeProperty ( dpy, w, _NET_WM_STATE(),
    XA_ATOM, 32, PropModeReplace, (unsigned char*)a, 2);
  XSync(dpy,False);
  }

X11Api::X11Api() {
  dpy = XOpenDisplay(nullptr);

  if(dpy == nullptr)
    throw std::runtime_error("cannot connect to X server!");

  root = DefaultRootWindow(dpy);

  static const TranslateKeyPair k[] = {
    { XK_KP_Left,   Event::K_Left     },
    { XK_KP_Right,  Event::K_Right    },
    { XK_KP_Up,     Event::K_Up       },
    { XK_KP_Down,   Event::K_Down     },

    { XK_Shift_L,   Event::K_LShift   },
    { XK_Shift_R,   Event::K_RShift   },

    { XK_Control_L, Event::K_LControl },
    { XK_Control_R, Event::K_RControl },

    { XK_Escape,    Event::K_ESCAPE   },
    { XK_Tab,       Event::K_Tab      },
    { XK_BackSpace, Event::K_Back     },
    { XK_Delete,    Event::K_Delete   },
    { XK_Insert,    Event::K_Insert   },
    { XK_Home,      Event::K_Home     },
    { XK_End,       Event::K_End      },
    { XK_Pause,     Event::K_Pause    },
    { XK_Return,    Event::K_Return   },

    { XK_F1,        Event::K_F1       },
    {   48,         Event::K_0        },
    {   97,         Event::K_A        },

    { 0,            Event::K_NoKey    }
    };

  setupKeyTranslate(k,24);
  }

void *X11Api::display() {
  return dpy;
  }

void X11Api::alignGeometry(SystemApi::Window *w, Tempest::Window& owner) {
  XWindowAttributes xwa={};
  if(XGetWindowAttributes(dpy, HWND(w), &xwa)){
    Tempest::SizeEvent e(xwa.width, xwa.height);
    SystemApi::dispatchResize(owner,e);
    }
  }

SystemApi::Window *X11Api::implCreateWindow(Tempest::Window *owner, uint32_t w, uint32_t h) {
  //GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  //XVisualInfo * vi = glXChooseVisual(dpy, 0, att);

  long visualMask = VisualScreenMask;
  int numberOfVisuals;
  XVisualInfo vInfoTemplate = {};
  vInfoTemplate.screen = DefaultScreen(dpy);
  XVisualInfo * vi = XGetVisualInfo(dpy, visualMask, &vInfoTemplate, &numberOfVisuals);

  Colormap cmap;
  cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);

  XSetWindowAttributes swa={};
  swa.colormap   = cmap;
  swa.event_mask = PointerMotionMask | ExposureMask |
                   ButtonPressMask | ButtonReleaseMask |
                   KeyPressMask | KeyReleaseMask;

  HWND win = XCreateWindow( dpy, root, 0, 0, w, h,
                            0, vi->depth, InputOutput, vi->visual,
                            CWColormap | CWEventMask, &swa );
  XSetWMProtocols(dpy, win, &wmDeleteMessage(), 1);
  XStoreName(dpy, win, wndClassName);

  XFreeColormap( dpy, cmap );
  XFree(vi);

  auto ret = reinterpret_cast<SystemApi::Window*>(win.ptr());
  windows[ret] = owner;
  //maximizeWindow(win);
  XMapWindow(dpy, win);
  XSync(dpy,False);
  alignGeometry(win.ptr(),*owner);
  return ret;
  }

SystemApi::Window *X11Api::implCreateWindow(Tempest::Window *owner, SystemApi::ShowMode sm) {
  return implCreateWindow(owner,800,600); //TODO
  }

void X11Api::implDestroyWindow(SystemApi::Window *w) {
  windows.erase(w); //NOTE: X11 can send events to ded window
  XDestroyWindow(dpy, HWND(w));
  }

bool X11Api::implSetAsFullscreen(SystemApi::Window *w, bool fullScreen) {
  return false;
  }

bool X11Api::implIsFullscreen(SystemApi::Window *w) {
  return false;
  }

void X11Api::implSetCursorPosition(int x, int y) {
  // TODO
  }

void X11Api::implShowCursor(bool show) {
  // TODO
  }

Rect X11Api::implWindowClientRect(SystemApi::Window *w) {
  XWindowAttributes xwa;
  XGetWindowAttributes(dpy, HWND(w), &xwa);

  return Rect( xwa.x, xwa.y, xwa.width, xwa.height );
  }

void X11Api::implExit() {
  isExit.store(true);
  }

bool X11Api::implIsRunning() {
  return !isExit.load();
  }

int X11Api::implExec(SystemApi::AppCallBack &cb) {
  // main message loop
  while (!isExit.load()) {
    implProcessEvents(cb);
    }
  return 0;
  }

void X11Api::implProcessEvents(SystemApi::AppCallBack &cb) {
  // main message loop
  if(XPending(dpy)>0) {
    XEvent xev={};
    XNextEvent(dpy, &xev);

    HWND hWnd = xev.xclient.window;
    auto it = windows.find(hWnd.ptr());
    if(it==windows.end() || it->second==nullptr)
      return;
    Tempest::Window& cb = *it->second; //TODO: validation
    switch( xev.type ) {
      case ClientMessage: {
        if( xev.xclient.data.l[0] == long(wmDeleteMessage()) ){
          SystemApi::exit();
          }
        break;
        }
      case ButtonPress:
      case ButtonRelease: {
        bool isWheel = false;
        if( xev.type==ButtonPress && XPending(dpy) &&
            (xev.xbutton.button == Button4 || xev.xbutton.button == Button5) ){
          XEvent ev;
          XNextEvent(dpy, &ev);
          isWheel = (ev.type==ButtonRelease);
          }

        if( isWheel ){
          int ticks = 0;
          if( xev.xbutton.button == Button4 ) {
            ticks = 100;
            }
          else if ( xev.xbutton.button == Button5 ) {
            ticks = -100;
            }
          Tempest::MouseEvent e( xev.xbutton.x,
                                 xev.xbutton.y,
                                 Tempest::Event::ButtonNone,
                                 ticks,
                                 0,
                                 Event::MouseWheel );
          SystemApi::dispatchMouseWheel(cb, e);
          } else {
          MouseEvent e( xev.xbutton.x,
                        xev.xbutton.y,
                        toButton( xev.xbutton ),
                        0,
                        0,
                        xev.type==ButtonPress ? Event::MouseDown : Event::MouseUp );
          if(xev.type==ButtonPress)
            SystemApi::dispatchMouseDown(cb, e); else
            SystemApi::dispatchMouseUp(cb, e);
          }
        break;
        }
      case MotionNotify: {
        MouseEvent e( xev.xmotion.x,
                      xev.xmotion.y,
                      Event::ButtonNone,
                      0,
                      0,
                      Event::MouseMove  );
        SystemApi::dispatchMouseMove(cb, e);
        break;
        }
      case KeyPress:
      case KeyRelease: {
        int keysyms_per_keycode_return = 0;
        KeySym *ksym = XGetKeyboardMapping( dpy, KeyCode(xev.xkey.keycode),
                                            1,
                                            &keysyms_per_keycode_return );

        char txt[10]={};
        XLookupString(&xev.xkey, txt, sizeof(txt)-1, ksym, nullptr );

        auto u16 = TextCodec::toUtf16(txt); // TODO: remove dynamic allocation
        auto key = SystemApi::translateKey(*ksym);

        uint32_t scan = xev.xkey.keycode;

        Tempest::KeyEvent e(Event::KeyType(key),uint32_t(u16.size()>0 ? u16[0] : 0),Event::M_NoModifier,(xev.type==KeyPress) ? Event::KeyDown : Event::KeyUp);
        if(xev.type==KeyPress)
          SystemApi::dispatchKeyDown(cb,e,scan); else
          SystemApi::dispatchKeyUp  (cb,e,scan);
        break;
        }
      }

    std::this_thread::yield();
    } else {
    if(cb.onTimer()==0)
      std::this_thread::yield();
    for(auto& i:windows) {
      // artificial move/resize event
      alignGeometry(i.first,*i.second);
      SystemApi::dispatchRender(*i.second);
      }
    }
  }

#endif
<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) FFLAS-FFPACK
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */
#include <givaro/modular.h>
#include <recint/rint.h>
#include "fflas-ffpack/fflas-ffpack.h"
#include <stdlib.h>
#include <stdio.h>

template <class Field>
bool test (Givaro::Integer p, size_t kmax){
    Field F(p);
    FFLAS::MMHelper<Field, FFLAS::MMHelperAlgo::Auto, FFLAS::ModeCategories::DelayedTag> MMH(F, 0);
    size_t k = MMH.MaxDelayedDim(0);
    if (kmax!=k)
        F.write(std::cerr)<<": expected: "<<kmax<<" got: "<<k<<std::endl;
    return kmax == k;
}
int main() {

    bool ok=true;

        // kmax = floor(2^53 / (p-1)^2)
    // ok &= test<Givaro::Modular<double>  >(17,35184372088831);
    // ok &= test<Givaro::Modular<double>  >(65521,2098176);
    // ok &= test<Givaro::Modular<double>  >(67108859,2);
    //     // kmax = floor(2^53 / ((p-1)/2)^2)
    // ok &= test<Givaro::ModularBalanced<double>  >(17,140737488355327);
    // ok &= test<Givaro::ModularBalanced<double>  >(65521,8392705);
    // ok &= test<Givaro::ModularBalanced<double>  >(67108859,8);
    //     // kmax = floor(2^24 / (p-1)^2)
    // ok &= test<Givaro::Modular<float> > (17,65535);
    // ok &= test<Givaro::Modular<float> > (2039,4);
    //     // kmax = floor(2^24 / ((p-1)/2)^2)
    // ok &= test<Givaro::ModularBalanced<float> >(17,262143);
    // ok &= test<Givaro::ModularBalanced<float> > (2039,16);

    //    // kmax = floor(2^53 / (p-1)^2)
    // ok &= test<Givaro::Modular<int64_t>  >(17,36028797018963967);
    // ok &= test<Givaro::Modular<int64_t>  >(65521,2148532608);
    // ok &= test<Givaro::Modular<int64_t>  >(1147482977,7);
    //     // kmax = floor(2^53 / ((p-1)/2)^2)
    // ok &= test<Givaro::ModularBalanced<int64_t>  >(17,144115188075855871);
    // ok &= test<Givaro::ModularBalanced<int64_t>  >(65521,8594130432);
    // ok &= test<Givaro::ModularBalanced<int64_t>  >(1147482977,28);

    //    // kmax = floor(2^31 / (p-1)^2)
    // ok &= test<Givaro::Modular<int32_t>  >(17,8388607);
    // ok &= test<Givaro::Modular<int32_t>  >(24571,3);
    //     // kmax = floor(2^31 / ((p-1)/2)^2)
    // ok &= test<Givaro::ModularBalanced<int32_t>  >(17,33554431);
    // ok &= test<Givaro::ModularBalanced<int32_t>  >(24571,14);

    //    // kmax = maxsize_t
    // ok &= test<Givaro::Modular<Givaro::Integer>  >(17, std::numeric_limits<size_t>::max());
    // ok &= test<Givaro::Modular<Givaro::Integer>  >(Givaro::Integer("46768052394588893382517914646921056628989841375373"),std::numeric_limits<size_t>::max());
    //     // kmax = maxsize_t
    ok &= test<Givaro::Modular<RecInt::rint<8> > >(17, std::numeric_limits<size_t>::max());
    ok &= test<Givaro::Modular<RecInt::rint<8> > >(Givaro::Integer("166153499473114484112975882535042793"),2097152);
    return !ok;
}

<commit_msg>revert most tests which were commented out (accidentally)<commit_after>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) FFLAS-FFPACK
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */
#include <givaro/modular.h>
#include <recint/rint.h>
#include "fflas-ffpack/fflas-ffpack.h"
#include <stdlib.h>
#include <stdio.h>

template <class Field>
bool test (Givaro::Integer p, size_t kmax){
    Field F(p);
    FFLAS::MMHelper<Field, FFLAS::MMHelperAlgo::Auto, FFLAS::ModeCategories::DelayedTag> MMH(F, 0);
    size_t k = MMH.MaxDelayedDim(0);
    if (kmax!=k)
        F.write(std::cerr)<<": expected: "<<kmax<<" got: "<<k<<std::endl;
    return kmax == k;
}
int main() {

    bool ok=true;

		// kmax = floor(2^53 / (p-1)^2)
    ok = ok && test<Givaro::Modular<double>  >(17,35184372088831);
    ok = ok && test<Givaro::Modular<double>  >(65521,2098176);
    ok = ok && test<Givaro::Modular<double>  >(67108859,2);
        // kmax = floor(2^53 / ((p-1)/2)^2)
    ok = ok && test<Givaro::ModularBalanced<double>  >(17,140737488355327);
    ok = ok && test<Givaro::ModularBalanced<double>  >(65521,8392705);
    ok = ok && test<Givaro::ModularBalanced<double>  >(67108859,8);
        // kmax = floor(2^24 / (p-1)^2)
    ok = ok && test<Givaro::Modular<float> > (17,65535);
    ok = ok && test<Givaro::Modular<float> > (2039,4);
        // kmax = floor(2^24 / ((p-1)/2)^2)
    ok = ok && test<Givaro::ModularBalanced<float> >(17,262143);
    ok = ok && test<Givaro::ModularBalanced<float> > (2039,16);

       // kmax = floor(2^53 / (p-1)^2)
    ok = ok && test<Givaro::Modular<int64_t>  >(17,36028797018963967);
    ok = ok && test<Givaro::Modular<int64_t>  >(65521,2148532608);
    ok = ok && test<Givaro::Modular<int64_t>  >(1147482977,7);
        // kmax = floor(2^53 / ((p-1)/2)^2)
    ok = ok && test<Givaro::ModularBalanced<int64_t>  >(17,144115188075855871);
    ok = ok && test<Givaro::ModularBalanced<int64_t>  >(65521,8594130432);
    ok = ok && test<Givaro::ModularBalanced<int64_t>  >(1147482977,28);

       // kmax = floor(2^31 / (p-1)^2)
    ok = ok && test<Givaro::Modular<int32_t>  >(17,8388607);
    ok = ok && test<Givaro::Modular<int32_t>  >(24571,3);
        // kmax = floor(2^31 / ((p-1)/2)^2)
    ok = ok && test<Givaro::ModularBalanced<int32_t>  >(17,33554431);
    ok = ok && test<Givaro::ModularBalanced<int32_t>  >(24571,14);

       // kmax = maxsize_t
    ok = ok && test<Givaro::Modular<Givaro::Integer>  >(17, std::numeric_limits<size_t>::max());
    ok = ok && test<Givaro::Modular<Givaro::Integer>  >(Givaro::Integer("46768052394588893382517914646921056628989841375373"),std::numeric_limits<size_t>::max());
        // kmax = maxsize_t
    ok = ok && test<Givaro::Modular<RecInt::rint<8> > >(17, std::numeric_limits<size_t>::max());
    ok = ok && test<Givaro::Modular<RecInt::rint<8> > >(Givaro::Integer("166153499473114484112975882535042793"),2097152);
    return !ok;
}

<|endoftext|>


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

#include "s2/third_party/absl/base/internal/raw_logging.h"

#include <cstddef>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include "s2/third_party/absl/base/attributes.h"
#include "s2/third_party/absl/base/config.h"
#include "s2/third_party/absl/base/internal/atomic_hook.h"
#include "s2/third_party/absl/base/log_severity.h"

// We know how to perform low-level writes to stderr in POSIX and Windows.  For
// these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED.
// Much of raw_logging.cc becomes a no-op when we can't output messages,
// although a FATAL ABSL_RAW_LOG message will still abort the process.

// ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write()
// (as from unistd.h)
//
// This preprocessor token is also defined in raw_io.cc.  If you need to copy
// this, consider moving both to config.h instead.
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
    defined(__Fuchsia__) || defined(__native_client__) || defined(__GENCLAVE__)
#include <unistd.h>

#define ABSL_HAVE_POSIX_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_POSIX_WRITE
#endif

// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
//   syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
// for low level operations that want to avoid libc.
#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
#include <sys/syscall.h>
#define ABSL_HAVE_SYSCALL_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_SYSCALL_WRITE
#endif

#ifdef _WIN32
#include <io.h>

#define ABSL_HAVE_RAW_IO 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_RAW_IO
#endif

// TODO(user): We want raw-logging to work on as many platforms as possible.
// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
// whitelisted set of platforms for which we expect not to be able to raw log.

ABSL_CONST_INIT static absl::base_internal::AtomicHook<
    absl::raw_logging_internal::LogPrefixHook> log_prefix_hook;
ABSL_CONST_INIT static absl::base_internal::AtomicHook<
    absl::raw_logging_internal::AbortHook> abort_hook;

#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
static const char kTruncated[] = " ... (message truncated)\n";

// sprintf the format to the buffer, adjusting *buf and *size to reflect the
// consumed bytes, and return whether the message fit without truncation.  If
// truncation occurred, if possible leave room in the buffer for the message
// kTruncated[].
inline static bool VADoRawLog(char** buf, int* size, const char* format,
                              va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
inline static bool VADoRawLog(char** buf, int* size,
                              const char* format, va_list ap) {
  int n = vsnprintf(*buf, *size, format, ap);
  bool result = true;
  if (n < 0 || n > *size) {
    result = false;
    if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
      n = *size - sizeof(kTruncated);  // room for truncation message
    } else {
      n = 0;                           // no room for truncation message
    }
  }
  *size -= n;
  *buf += n;
  return result;
}
#endif  // ABSL_LOW_LEVEL_WRITE_SUPPORTED

static constexpr int kLogBufSize = 3000;

namespace {

// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// If this becomes a problem we should reimplement a subset of vsnprintf
// that does not need locks and malloc.
// E.g. //third_party/clearsilver/core/util/snprintf.c
// looks like such a reimplementation.

// Helper for RawLog below.
// *DoRawLog writes to *buf of *size and move them past the written portion.
// It returns true iff there was no overflow or error.
bool DoRawLog(char** buf, int* size, const char* format, ...)
    ABSL_PRINTF_ATTRIBUTE(3, 4);
bool DoRawLog(char** buf, int* size, const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  int n = vsnprintf(*buf, *size, format, ap);
  va_end(ap);
  if (n < 0 || n > *size) return false;
  *size -= n;
  *buf += n;
  return true;
}

void RawLogVA(absl::LogSeverity severity, const char* file, int line,
              const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
void RawLogVA(absl::LogSeverity severity, const char* file, int line,
              const char* format, va_list ap) {
  char buffer[kLogBufSize];
  char* buf = buffer;
  int size = sizeof(buffer);
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
  bool enabled = true;
#else
  bool enabled = false;
#endif

#ifdef ABSL_MIN_LOG_LEVEL
  if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL &&
      severity < absl::LogSeverity::kFatal) {
    enabled = false;
  }
#endif

  auto log_prefix_hook_ptr = log_prefix_hook.Load();
  if (log_prefix_hook_ptr) {
    enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size);
  } else {
    if (enabled) {
      DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line);
    }
  }
  const char* const prefix_end = buf;

#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
  if (enabled) {
    bool no_chop = VADoRawLog(&buf, &size, format, ap);
    if (no_chop) {
      DoRawLog(&buf, &size, "\n");
    } else {
      DoRawLog(&buf, &size, "%s", kTruncated);
    }
    absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
  }
#else
  static_cast<void>(format);
  static_cast<void>(ap);
#endif

  // Abort the process after logging a FATAL message, even if the output itself
  // was suppressed.
  if (severity == absl::LogSeverity::kFatal) {
    abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize);
    abort();
  }
}

}  // namespace

namespace absl {
namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE)
  syscall(SYS_write, STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_POSIX_WRITE)
  write(STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_RAW_IO)
  _write(/* stderr */ 2, s, len);
#else
  // stderr logging unsupported on this platform
  (void) s;
  (void) len;
#endif
}

void RawLog(absl::LogSeverity severity, const char* file, int line,
            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
void RawLog(absl::LogSeverity severity, const char* file, int line,
            const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(severity, file, line, format, ap);
  va_end(ap);
}
void RawLog(int severity, const char* file, int line, const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(absl::NormalizeLogSeverity(severity), file, line, format, ap);
  va_end(ap);
}

bool RawLoggingFullySupported() {
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
  return true;
#else  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
  return false;
#endif  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
}

}  // namespace raw_logging_internal
}  // namespace absl

namespace base_raw_logging {

void RawLog(absl::LogSeverity severity, const char* file, int line,
            const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(severity, file, line, format, ap);
  va_end(ap);
}
void RawLog(int severity, const char* file, int line, const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(absl::NormalizeLogSeverity(severity), file, line, format, ap);
  va_end(ap);
}

void RegisterLogPrefixHook(LogPrefixHook fn) {
  log_prefix_hook.Store(fn);
}

void RegisterAbortHook(AbortHook fn) {
  abort_hook.Store(fn);
}
}  // namespace base_raw_logging

<commit_msg>absl: Use __ASYLO__ instead of __GENCLAVE__.<commit_after>// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "s2/third_party/absl/base/internal/raw_logging.h"

#include <cstddef>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include "s2/third_party/absl/base/attributes.h"
#include "s2/third_party/absl/base/config.h"
#include "s2/third_party/absl/base/internal/atomic_hook.h"
#include "s2/third_party/absl/base/log_severity.h"

// We know how to perform low-level writes to stderr in POSIX and Windows.  For
// these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED.
// Much of raw_logging.cc becomes a no-op when we can't output messages,
// although a FATAL ABSL_RAW_LOG message will still abort the process.

// ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write()
// (as from unistd.h)
//
// This preprocessor token is also defined in raw_io.cc.  If you need to copy
// this, consider moving both to config.h instead.
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
    defined(__Fuchsia__) || defined(__native_client__) || defined(__ASYLO__)
#include <unistd.h>

#define ABSL_HAVE_POSIX_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_POSIX_WRITE
#endif

// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
//   syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
// for low level operations that want to avoid libc.
#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
#include <sys/syscall.h>
#define ABSL_HAVE_SYSCALL_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_SYSCALL_WRITE
#endif

#ifdef _WIN32
#include <io.h>

#define ABSL_HAVE_RAW_IO 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_RAW_IO
#endif

// TODO(user): We want raw-logging to work on as many platforms as possible.
// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
// whitelisted set of platforms for which we expect not to be able to raw log.

ABSL_CONST_INIT static absl::base_internal::AtomicHook<
    absl::raw_logging_internal::LogPrefixHook> log_prefix_hook;
ABSL_CONST_INIT static absl::base_internal::AtomicHook<
    absl::raw_logging_internal::AbortHook> abort_hook;

#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
static const char kTruncated[] = " ... (message truncated)\n";

// sprintf the format to the buffer, adjusting *buf and *size to reflect the
// consumed bytes, and return whether the message fit without truncation.  If
// truncation occurred, if possible leave room in the buffer for the message
// kTruncated[].
inline static bool VADoRawLog(char** buf, int* size, const char* format,
                              va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
inline static bool VADoRawLog(char** buf, int* size,
                              const char* format, va_list ap) {
  int n = vsnprintf(*buf, *size, format, ap);
  bool result = true;
  if (n < 0 || n > *size) {
    result = false;
    if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
      n = *size - sizeof(kTruncated);  // room for truncation message
    } else {
      n = 0;                           // no room for truncation message
    }
  }
  *size -= n;
  *buf += n;
  return result;
}
#endif  // ABSL_LOW_LEVEL_WRITE_SUPPORTED

static constexpr int kLogBufSize = 3000;

namespace {

// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// If this becomes a problem we should reimplement a subset of vsnprintf
// that does not need locks and malloc.
// E.g. //third_party/clearsilver/core/util/snprintf.c
// looks like such a reimplementation.

// Helper for RawLog below.
// *DoRawLog writes to *buf of *size and move them past the written portion.
// It returns true iff there was no overflow or error.
bool DoRawLog(char** buf, int* size, const char* format, ...)
    ABSL_PRINTF_ATTRIBUTE(3, 4);
bool DoRawLog(char** buf, int* size, const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  int n = vsnprintf(*buf, *size, format, ap);
  va_end(ap);
  if (n < 0 || n > *size) return false;
  *size -= n;
  *buf += n;
  return true;
}

void RawLogVA(absl::LogSeverity severity, const char* file, int line,
              const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
void RawLogVA(absl::LogSeverity severity, const char* file, int line,
              const char* format, va_list ap) {
  char buffer[kLogBufSize];
  char* buf = buffer;
  int size = sizeof(buffer);
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
  bool enabled = true;
#else
  bool enabled = false;
#endif

#ifdef ABSL_MIN_LOG_LEVEL
  if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL &&
      severity < absl::LogSeverity::kFatal) {
    enabled = false;
  }
#endif

  auto log_prefix_hook_ptr = log_prefix_hook.Load();
  if (log_prefix_hook_ptr) {
    enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size);
  } else {
    if (enabled) {
      DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line);
    }
  }
  const char* const prefix_end = buf;

#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
  if (enabled) {
    bool no_chop = VADoRawLog(&buf, &size, format, ap);
    if (no_chop) {
      DoRawLog(&buf, &size, "\n");
    } else {
      DoRawLog(&buf, &size, "%s", kTruncated);
    }
    absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
  }
#else
  static_cast<void>(format);
  static_cast<void>(ap);
#endif

  // Abort the process after logging a FATAL message, even if the output itself
  // was suppressed.
  if (severity == absl::LogSeverity::kFatal) {
    abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize);
    abort();
  }
}

}  // namespace

namespace absl {
namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE)
  syscall(SYS_write, STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_POSIX_WRITE)
  write(STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_RAW_IO)
  _write(/* stderr */ 2, s, len);
#else
  // stderr logging unsupported on this platform
  (void) s;
  (void) len;
#endif
}

void RawLog(absl::LogSeverity severity, const char* file, int line,
            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
void RawLog(absl::LogSeverity severity, const char* file, int line,
            const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(severity, file, line, format, ap);
  va_end(ap);
}
void RawLog(int severity, const char* file, int line, const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(absl::NormalizeLogSeverity(severity), file, line, format, ap);
  va_end(ap);
}

bool RawLoggingFullySupported() {
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
  return true;
#else  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
  return false;
#endif  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
}

}  // namespace raw_logging_internal
}  // namespace absl

namespace base_raw_logging {

void RawLog(absl::LogSeverity severity, const char* file, int line,
            const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(severity, file, line, format, ap);
  va_end(ap);
}
void RawLog(int severity, const char* file, int line, const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  RawLogVA(absl::NormalizeLogSeverity(severity), file, line, format, ap);
  va_end(ap);
}

void RegisterLogPrefixHook(LogPrefixHook fn) {
  log_prefix_hook.Store(fn);
}

void RegisterAbortHook(AbortHook fn) {
  abort_hook.Store(fn);
}
}  // namespace base_raw_logging

<|endoftext|>