<commit_before>#include "AliAODExtension.h"

//-------------------------------------------------------------------------
//     Support class for AOD extensions. This is created by the user analysis
//     that requires a separate file for some AOD branches. The name of the
//     AliAODExtension object is the file name where the AOD branches will be
//     stored.
//-------------------------------------------------------------------------

#include "AliAODBranchReplicator.h"
#include "AliAODEvent.h"
#include "AliCodeTimer.h"
#include "AliLog.h"
#include "Riostream.h"
#include "TDirectory.h"
#include "TFile.h"
#include "TList.h"
#include "TMap.h"
#include "TMap.h"
#include "TObjString.h"
#include "TROOT.h"
#include "TString.h"
#include "TTree.h"

using std::endl;
using std::cout;
ClassImp(AliAODExtension)

//______________________________________________________________________________
AliAODExtension::AliAODExtension() : TNamed(),
fAODEvent(0), fTreeE(0), fFileE(0), fNtotal(0), fNpassed(0),
fSelected(kFALSE), fTreeBuffSize(30000000), fMemCountAOD(0),
fRepFiMap(0x0), fRepFiList(0x0), fEnableReferences(kTRUE)
{
  // default ctor
}

//______________________________________________________________________________
AliAODExtension::AliAODExtension(const char* name, const char* title, Bool_t isfilter)
:TNamed(name,title),
fAODEvent(0),
fTreeE(0),
fFileE(0),
fNtotal(0),
fNpassed(0),
fSelected(kFALSE),
fTreeBuffSize(30000000),
fMemCountAOD(0),
fRepFiMap(0x0),
fRepFiList(0x0),
fEnableReferences(kTRUE),
fObjectList(0x0)
{
  // Constructor.
  if (isfilter) {
    TObject::SetBit(kFilteredAOD);
    printf("####### Added AOD filter %s\n", name);
  } else printf("####### Added AOD extension %s\n", name);
  KeepUnspecifiedBranches();
}

//______________________________________________________________________________
AliAODExtension::~AliAODExtension()
{
  // Destructor.
  if(fFileE){
    // is already handled in TerminateIO
    fFileE->Close();
    delete fFileE;
    fTreeE = 0;
    fAODEvent = 0;
  }
  if (fTreeE) delete fTreeE;
  if (fRepFiMap) fRepFiMap->DeleteAll();
  delete fRepFiMap; // the map is owner
  delete fRepFiList; // the list is not
  delete fObjectList; // not owner
}

//______________________________________________________________________________
void AliAODExtension::AddBranch(const char* cname, void* addobj)
{
  // Add a new branch to the aod

  if (!fAODEvent) {
    char type[20];
    gROOT->ProcessLine(Form("TString s_tmp; AliAnalysisManager::GetAnalysisManager()->GetAnalysisTypeString(s_tmp); sprintf((char*)%p, \"%%s\", s_tmp.Data());", type));
    Init(type);
  }
  TDirectory *owd = gDirectory;
  if (fFileE) {
    fFileE->cd();
  }
  char** apointer = (char**) addobj;
  TObject* obj = (TObject*) *apointer;

  fAODEvent->AddObject(obj);

  TString bname(obj->GetName());

  if (!fTreeE->FindBranch(bname.Data()))
  {
    Bool_t acceptAdd(kTRUE);

    if ( TestBit(kDropUnspecifiedBranches) )
    {
      // check that this branch is in our list of specified ones...
      // otherwise do not add it !
      TIter next(fRepFiMap);
      TObjString* p;

      acceptAdd=kFALSE;

      while ( ( p = static_cast<TObjString*>(next()) ) && !acceptAdd )
      {
        if ( p->String() == bname ) acceptAdd=kTRUE;
      }
    }

    if ( acceptAdd )
    {
      // Do the same as if we book via
      // TTree::Branch(TCollection*)

      fObjectList->Add(obj);

      const Int_t kSplitlevel = 99; // default value in TTree::Branch()
      const Int_t kBufsize = 32000; // default value in TTree::Branch()

      fTreeE->Bronch(bname.Data(), cname,
                     fAODEvent->GetList()->GetObjectRef(obj),
                     kBufsize, kSplitlevel - 1);
    }
  }
  owd->cd();
}

//______________________________________________________________________________
Bool_t AliAODExtension::FinishEvent()
{
  // Fill current event.
  fNtotal++;
  if (!IsFilteredAOD()) {
    fAODEvent->MakeEntriesReferencable();
    FillTree();
    return kTRUE;
  }
  // Filtered AOD. Fill only if event is selected.
  if (!fSelected) return kTRUE;

  TIter next(fRepFiList);

  AliAODBranchReplicator* repfi;

  while ( ( repfi = static_cast<AliAODBranchReplicator*>(next()) ) )
  {
    repfi->ReplicateAndFilter(*fAODEvent);
  }
  fNpassed++;
  FillTree();
  fSelected = kFALSE; // so that next event will not be selected unless demanded
  return kTRUE;
}

//______________________________________________________________________________
void AliAODExtension::FillTree()
{
  //
  //   Fill AOD extension tree and check AutoFlush settings
  //

  Long64_t nbf = fTreeE->Fill();

  // Check buffer size and set autoflush if fTreeBuffSize is reached
  if (fTreeBuffSize>0 && fTreeE->GetAutoFlush()<0 &&
      (fMemCountAOD += nbf)>fTreeBuffSize ) { // default limit is still not reached
    nbf = fTreeE->GetZipBytes();
    if (nbf>0) nbf = -nbf;
    else       nbf = fTreeE->GetEntries();
    fTreeE->SetAutoFlush(nbf);
    AliInfo(Form("Calling fTreeE->SetAutoFlush(%lld) | W:%lld T:%lld Z:%lld",
		 nbf,fMemCountAOD,fTreeE->GetTotBytes(),fTreeE->GetZipBytes()));

  }
}

//______________________________________________________________________________
Bool_t AliAODExtension::Init(Option_t *option)
{
  // Initialize IO.

  AliCodeTimerAuto(GetName(),0);

  if(!fAODEvent)
  {
    fAODEvent = new AliAODEvent();
  }

  TDirectory *owd = gDirectory;
  TString opt(option);
  opt.ToLower();

  if (opt.Contains("proof"))
  {
    // proof
    // Merging via files. Need to access analysis manager via interpreter.
    gROOT->ProcessLine(Form("AliAnalysisDataContainer *c_common_out = AliAnalysisManager::GetAnalysisManager()->GetCommonOutputContainer();"));
    gROOT->ProcessLine(Form("AliAnalysisManager::GetAnalysisManager()->OpenProofFile(c_common_out, \"RECREATE\", \"%s\");", fName.Data()));
    fFileE = gFile;
  }
  else
  {
    fFileE = new TFile(GetName(), "RECREATE");
  }
  fTreeE = new TTree("aodTree", "AliAOD tree");

  delete fObjectList;
  fObjectList = new TList;
  fObjectList->SetOwner(kFALSE); // be explicit we're not the owner...
  TList* inputList = fAODEvent->GetList();
  TIter next(inputList);
  TObject* o;

  while ( ( o = next() ) )
  {
    // Loop on the objects that are within the main AOD, and see what to do with them :
    // - transmit them to our AOD as they are
    // - filter them (by means of an AliAODBranchReplicator)
    // - drop them completely

    Bool_t mustKeep(kFALSE);

    TString test(o->ClassName());
    test.ToUpper();
    // check if there is a replicator for the header
    Bool_t headerHasReplicator = fRepFiMap && (fRepFiMap->FindObject(o->GetName())!=0x0);
    if (test.BeginsWith("ALIAODHEADER") && !headerHasReplicator)
    {
      // do not allow to drop header branch
      mustKeep=kTRUE;
    }

    if ( fRepFiMap && !mustKeep )
    {
      // we have some replicators, so let's see what the relevant one decides about this object
      TObject* specified = fRepFiMap->FindObject(o->GetName()); // FindObject finds key=o->GetName() in the map
      if (specified)
      {
        AliAODBranchReplicator* repfi = dynamic_cast<AliAODBranchReplicator*>(fRepFiMap->GetValue(o->GetName())); // GetValue gets the replicator corresponding to key=o->GetName()
        if ( repfi )
        {
          TList* replicatedList = repfi->GetList();
          if (replicatedList)
          {
            AliAODEvent::AssignIDtoCollection(replicatedList);
            TIter nextRep(replicatedList);
            TObject* objRep;
            while ( ( objRep = nextRep() ) )
            {
              if ( !fObjectList->FindObject(objRep) ) // insure we're not adding several times the same object
              {
                fObjectList->Add(objRep);
              }
            }
          }
          else
          {
            AliError(Form("replicatedList from %s is null !",repfi->GetName()));
          }
        }
      }
      else
      {
        if ( !TestBit(kDropUnspecifiedBranches) )
        {
          // object o will be transmitted to the output AOD, unchanged
          fObjectList->Add(o);
        }
      }
    }
    else
    {
      // no replicator, so decide based on the policy about dropping unspecified branches
      if ( mustKeep || !TestBit(kDropUnspecifiedBranches) )
      {
        // object o will be transmitted to the output AOD, unchanged
        fObjectList->Add(o);
      }
    }
  }

  if (fEnableReferences)
  {
    fTreeE->BranchRef();
  }

  fTreeE->Branch(fObjectList);

  owd->cd();

  return kTRUE;
}

//______________________________________________________________________________
void AliAODExtension::Print(Option_t* opt) const
{
  // Print info about this extension

  cout << opt << Form("%s - %s - %s - aod %p",IsFilteredAOD() ? "FilteredAOD" : "Extension",
                      GetName(),GetTitle(),GetAOD()) << endl;
  if ( !fEnableReferences )
  {
    cout << opt << opt << "References are disabled ! Hope you know what you are doing !" << endl;
  }
  if ( TestBit(kDropUnspecifiedBranches) )
  {
    cout << opt << opt << "All branches not explicitely specified will be dropped" << endl;
  }

  TIter next(fRepFiMap);
  TObjString* s;

  while ( ( s = static_cast<TObjString*>(next()) ) )
  {
    AliAODBranchReplicator* br = static_cast<AliAODBranchReplicator*>(fRepFiMap->GetValue(s->String().Data()));

    cout << opt << opt << "Branch " << s->String();
    if (br)
    {
      cout << " will be filtered by class " << br->ClassName();
    }
    else
    {
      cout << " will be transmitted as is";
    }
    cout << endl;
  }
}

//______________________________________________________________________________
void AliAODExtension::SetEvent(AliAODEvent* event)
{
  // Connects to an external event
  if (!IsFilteredAOD()) {
    Error("SetEvent", "Not allowed to set external event for non filtered AOD's");
    return;
  }
  fAODEvent = event;
}

//______________________________________________________________________________
void AliAODExtension::AddAODtoTreeUserInfo()
{
  // Add aod event to tree user info

  if (!fTreeE) return;

  AliAODEvent* aodEvent(fAODEvent);

  if ( IsFilteredAOD() )
  {
    // cannot attach fAODEvent (which is shared with our AliAODHandler mother)
    // so we create a custom (empty) AliAODEvent
    // Has also the advantage we can specify only the list of objects
    // that are actually there in this filtered aod
    //
    aodEvent = new AliAODEvent;
    TIter nextObj(fObjectList);
    TObject* o;
    while ( ( o = nextObj() ) )
    {
      aodEvent->AddObject(o);
    }
  }

  fTreeE->GetUserInfo()->Add(aodEvent);
}

//______________________________________________________________________________
Bool_t AliAODExtension::TerminateIO()
{
  // Terminate IO
  if (TObject::TestBit(kFilteredAOD))
    printf("AOD Filter %s: events processed: %d   passed: %d\n", GetName(), fNtotal, fNpassed);
  else
    printf("AOD extension %s: events processed: %d\n", GetName(), fNtotal);
  if (fFileE)
  {
    fFileE->Write();
    fFileE->Close();
    delete fFileE;
    fFileE = 0;
    fTreeE = 0;
    fAODEvent = 0;
  }
  return kTRUE;
}

//______________________________________________________________________________
void AliAODExtension::FilterBranch(const char* branchName, AliAODBranchReplicator* repfi)
{
  // Specify a filter/replicator for a given branch
  //
  // If repfi=0x0, this will disable the branch (in the output) completely.
  //
  // repfi is adopted by this class, i.e. user should not delete it.
  //
  // WARNING : branch name must be exact.
  //
  // See also the documentation for AliAODBranchReplicator class.
  //

  if (!fRepFiMap)
  {
    fRepFiMap = new TMap;
    fRepFiMap->SetOwnerKeyValue(kTRUE,kTRUE);
    fRepFiList = new TList;
    fRepFiList->SetOwner(kFALSE);
  }

  fRepFiMap->Add(new TObjString(branchName),repfi);

  if (repfi && !fRepFiList->FindObject(repfi))
  {
    // insure we get unique and non-null replicators in this list
    fRepFiList->Add(repfi);
  }
}

<commit_msg>Fixed Coverity defect<commit_after>#include "AliAODExtension.h"

//-------------------------------------------------------------------------
//     Support class for AOD extensions. This is created by the user analysis
//     that requires a separate file for some AOD branches. The name of the
//     AliAODExtension object is the file name where the AOD branches will be
//     stored.
//-------------------------------------------------------------------------

#include "AliAODBranchReplicator.h"
#include "AliAODEvent.h"
#include "AliCodeTimer.h"
#include "AliLog.h"
#include "Riostream.h"
#include "TDirectory.h"
#include "TFile.h"
#include "TList.h"
#include "TMap.h"
#include "TMap.h"
#include "TObjString.h"
#include "TROOT.h"
#include "TString.h"
#include "TTree.h"

using std::endl;
using std::cout;
ClassImp(AliAODExtension)

//______________________________________________________________________________
AliAODExtension::AliAODExtension() : TNamed(),
fAODEvent(0), fTreeE(0), fFileE(0), fNtotal(0), fNpassed(0),
fSelected(kFALSE), fTreeBuffSize(30000000), fMemCountAOD(0),
fRepFiMap(0x0), fRepFiList(0x0), fEnableReferences(kTRUE), fObjectList(0)
{
  // default ctor
}

//______________________________________________________________________________
AliAODExtension::AliAODExtension(const char* name, const char* title, Bool_t isfilter)
:TNamed(name,title),
fAODEvent(0),
fTreeE(0),
fFileE(0),
fNtotal(0),
fNpassed(0),
fSelected(kFALSE),
fTreeBuffSize(30000000),
fMemCountAOD(0),
fRepFiMap(0x0),
fRepFiList(0x0),
fEnableReferences(kTRUE),
fObjectList(0x0)
{
  // Constructor.
  if (isfilter) {
    TObject::SetBit(kFilteredAOD);
    printf("####### Added AOD filter %s\n", name);
  } else printf("####### Added AOD extension %s\n", name);
  KeepUnspecifiedBranches();
}

//______________________________________________________________________________
AliAODExtension::~AliAODExtension()
{
  // Destructor.
  if(fFileE){
    // is already handled in TerminateIO
    fFileE->Close();
    delete fFileE;
    fTreeE = 0;
    fAODEvent = 0;
  }
  if (fTreeE) delete fTreeE;
  if (fRepFiMap) fRepFiMap->DeleteAll();
  delete fRepFiMap; // the map is owner
  delete fRepFiList; // the list is not
  delete fObjectList; // not owner
}

//______________________________________________________________________________
void AliAODExtension::AddBranch(const char* cname, void* addobj)
{
  // Add a new branch to the aod

  if (!fAODEvent) {
    char type[20];
    gROOT->ProcessLine(Form("TString s_tmp; AliAnalysisManager::GetAnalysisManager()->GetAnalysisTypeString(s_tmp); sprintf((char*)%p, \"%%s\", s_tmp.Data());", type));
    Init(type);
  }
  TDirectory *owd = gDirectory;
  if (fFileE) {
    fFileE->cd();
  }
  char** apointer = (char**) addobj;
  TObject* obj = (TObject*) *apointer;

  fAODEvent->AddObject(obj);

  TString bname(obj->GetName());

  if (!fTreeE->FindBranch(bname.Data()))
  {
    Bool_t acceptAdd(kTRUE);

    if ( TestBit(kDropUnspecifiedBranches) )
    {
      // check that this branch is in our list of specified ones...
      // otherwise do not add it !
      TIter next(fRepFiMap);
      TObjString* p;

      acceptAdd=kFALSE;

      while ( ( p = static_cast<TObjString*>(next()) ) && !acceptAdd )
      {
        if ( p->String() == bname ) acceptAdd=kTRUE;
      }
    }

    if ( acceptAdd )
    {
      // Do the same as if we book via
      // TTree::Branch(TCollection*)

      fObjectList->Add(obj);

      const Int_t kSplitlevel = 99; // default value in TTree::Branch()
      const Int_t kBufsize = 32000; // default value in TTree::Branch()

      fTreeE->Bronch(bname.Data(), cname,
                     fAODEvent->GetList()->GetObjectRef(obj),
                     kBufsize, kSplitlevel - 1);
    }
  }
  owd->cd();
}

//______________________________________________________________________________
Bool_t AliAODExtension::FinishEvent()
{
  // Fill current event.
  fNtotal++;
  if (!IsFilteredAOD()) {
    fAODEvent->MakeEntriesReferencable();
    FillTree();
    return kTRUE;
  }
  // Filtered AOD. Fill only if event is selected.
  if (!fSelected) return kTRUE;

  TIter next(fRepFiList);

  AliAODBranchReplicator* repfi;

  while ( ( repfi = static_cast<AliAODBranchReplicator*>(next()) ) )
  {
    repfi->ReplicateAndFilter(*fAODEvent);
  }
  fNpassed++;
  FillTree();
  fSelected = kFALSE; // so that next event will not be selected unless demanded
  return kTRUE;
}

//______________________________________________________________________________
void AliAODExtension::FillTree()
{
  //
  //   Fill AOD extension tree and check AutoFlush settings
  //

  Long64_t nbf = fTreeE->Fill();

  // Check buffer size and set autoflush if fTreeBuffSize is reached
  if (fTreeBuffSize>0 && fTreeE->GetAutoFlush()<0 &&
      (fMemCountAOD += nbf)>fTreeBuffSize ) { // default limit is still not reached
    nbf = fTreeE->GetZipBytes();
    if (nbf>0) nbf = -nbf;
    else       nbf = fTreeE->GetEntries();
    fTreeE->SetAutoFlush(nbf);
    AliInfo(Form("Calling fTreeE->SetAutoFlush(%lld) | W:%lld T:%lld Z:%lld",
		 nbf,fMemCountAOD,fTreeE->GetTotBytes(),fTreeE->GetZipBytes()));

  }
}

//______________________________________________________________________________
Bool_t AliAODExtension::Init(Option_t *option)
{
  // Initialize IO.

  AliCodeTimerAuto(GetName(),0);

  if(!fAODEvent)
  {
    fAODEvent = new AliAODEvent();
  }

  TDirectory *owd = gDirectory;
  TString opt(option);
  opt.ToLower();

  if (opt.Contains("proof"))
  {
    // proof
    // Merging via files. Need to access analysis manager via interpreter.
    gROOT->ProcessLine(Form("AliAnalysisDataContainer *c_common_out = AliAnalysisManager::GetAnalysisManager()->GetCommonOutputContainer();"));
    gROOT->ProcessLine(Form("AliAnalysisManager::GetAnalysisManager()->OpenProofFile(c_common_out, \"RECREATE\", \"%s\");", fName.Data()));
    fFileE = gFile;
  }
  else
  {
    fFileE = new TFile(GetName(), "RECREATE");
  }
  fTreeE = new TTree("aodTree", "AliAOD tree");

  delete fObjectList;
  fObjectList = new TList;
  fObjectList->SetOwner(kFALSE); // be explicit we're not the owner...
  TList* inputList = fAODEvent->GetList();
  TIter next(inputList);
  TObject* o;

  while ( ( o = next() ) )
  {
    // Loop on the objects that are within the main AOD, and see what to do with them :
    // - transmit them to our AOD as they are
    // - filter them (by means of an AliAODBranchReplicator)
    // - drop them completely

    Bool_t mustKeep(kFALSE);

    TString test(o->ClassName());
    test.ToUpper();
    // check if there is a replicator for the header
    Bool_t headerHasReplicator = fRepFiMap && (fRepFiMap->FindObject(o->GetName())!=0x0);
    if (test.BeginsWith("ALIAODHEADER") && !headerHasReplicator)
    {
      // do not allow to drop header branch
      mustKeep=kTRUE;
    }

    if ( fRepFiMap && !mustKeep )
    {
      // we have some replicators, so let's see what the relevant one decides about this object
      TObject* specified = fRepFiMap->FindObject(o->GetName()); // FindObject finds key=o->GetName() in the map
      if (specified)
      {
        AliAODBranchReplicator* repfi = dynamic_cast<AliAODBranchReplicator*>(fRepFiMap->GetValue(o->GetName())); // GetValue gets the replicator corresponding to key=o->GetName()
        if ( repfi )
        {
          TList* replicatedList = repfi->GetList();
          if (replicatedList)
          {
            AliAODEvent::AssignIDtoCollection(replicatedList);
            TIter nextRep(replicatedList);
            TObject* objRep;
            while ( ( objRep = nextRep() ) )
            {
              if ( !fObjectList->FindObject(objRep) ) // insure we're not adding several times the same object
              {
                fObjectList->Add(objRep);
              }
            }
          }
          else
          {
            AliError(Form("replicatedList from %s is null !",repfi->GetName()));
          }
        }
      }
      else
      {
        if ( !TestBit(kDropUnspecifiedBranches) )
        {
          // object o will be transmitted to the output AOD, unchanged
          fObjectList->Add(o);
        }
      }
    }
    else
    {
      // no replicator, so decide based on the policy about dropping unspecified branches
      if ( mustKeep || !TestBit(kDropUnspecifiedBranches) )
      {
        // object o will be transmitted to the output AOD, unchanged
        fObjectList->Add(o);
      }
    }
  }

  if (fEnableReferences)
  {
    fTreeE->BranchRef();
  }

  fTreeE->Branch(fObjectList);

  owd->cd();

  return kTRUE;
}

//______________________________________________________________________________
void AliAODExtension::Print(Option_t* opt) const
{
  // Print info about this extension

  cout << opt << Form("%s - %s - %s - aod %p",IsFilteredAOD() ? "FilteredAOD" : "Extension",
                      GetName(),GetTitle(),GetAOD()) << endl;
  if ( !fEnableReferences )
  {
    cout << opt << opt << "References are disabled ! Hope you know what you are doing !" << endl;
  }
  if ( TestBit(kDropUnspecifiedBranches) )
  {
    cout << opt << opt << "All branches not explicitely specified will be dropped" << endl;
  }

  TIter next(fRepFiMap);
  TObjString* s;

  while ( ( s = static_cast<TObjString*>(next()) ) )
  {
    AliAODBranchReplicator* br = static_cast<AliAODBranchReplicator*>(fRepFiMap->GetValue(s->String().Data()));

    cout << opt << opt << "Branch " << s->String();
    if (br)
    {
      cout << " will be filtered by class " << br->ClassName();
    }
    else
    {
      cout << " will be transmitted as is";
    }
    cout << endl;
  }
}

//______________________________________________________________________________
void AliAODExtension::SetEvent(AliAODEvent* event)
{
  // Connects to an external event
  if (!IsFilteredAOD()) {
    Error("SetEvent", "Not allowed to set external event for non filtered AOD's");
    return;
  }
  fAODEvent = event;
}

//______________________________________________________________________________
void AliAODExtension::AddAODtoTreeUserInfo()
{
  // Add aod event to tree user info

  if (!fTreeE) return;

  AliAODEvent* aodEvent(fAODEvent);

  if ( IsFilteredAOD() )
  {
    // cannot attach fAODEvent (which is shared with our AliAODHandler mother)
    // so we create a custom (empty) AliAODEvent
    // Has also the advantage we can specify only the list of objects
    // that are actually there in this filtered aod
    //
    aodEvent = new AliAODEvent;
    TIter nextObj(fObjectList);
    TObject* o;
    while ( ( o = nextObj() ) )
    {
      aodEvent->AddObject(o);
    }
  }

  fTreeE->GetUserInfo()->Add(aodEvent);
}

//______________________________________________________________________________
Bool_t AliAODExtension::TerminateIO()
{
  // Terminate IO
  if (TObject::TestBit(kFilteredAOD))
    printf("AOD Filter %s: events processed: %d   passed: %d\n", GetName(), fNtotal, fNpassed);
  else
    printf("AOD extension %s: events processed: %d\n", GetName(), fNtotal);
  if (fFileE)
  {
    fFileE->Write();
    fFileE->Close();
    delete fFileE;
    fFileE = 0;
    fTreeE = 0;
    fAODEvent = 0;
  }
  return kTRUE;
}

//______________________________________________________________________________
void AliAODExtension::FilterBranch(const char* branchName, AliAODBranchReplicator* repfi)
{
  // Specify a filter/replicator for a given branch
  //
  // If repfi=0x0, this will disable the branch (in the output) completely.
  //
  // repfi is adopted by this class, i.e. user should not delete it.
  //
  // WARNING : branch name must be exact.
  //
  // See also the documentation for AliAODBranchReplicator class.
  //

  if (!fRepFiMap)
  {
    fRepFiMap = new TMap;
    fRepFiMap->SetOwnerKeyValue(kTRUE,kTRUE);
    fRepFiList = new TList;
    fRepFiList->SetOwner(kFALSE);
  }

  fRepFiMap->Add(new TObjString(branchName),repfi);

  if (repfi && !fRepFiList->FindObject(repfi))
  {
    // insure we get unique and non-null replicators in this list
    fRepFiList->Add(repfi);
  }
}

<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (C) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/
/**
 * @file main.cpp
 * Basic shell to execute builtin "apps"
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 * @author Roman Bapst <bapstroman@gmail.com>
 */

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include "apps.h"
#include "px4_middleware.h"
#include "DriverFramework.hpp"
#include <termios.h>

namespace px4
{
void init_once(void);
}

using namespace std;

typedef int (*px4_main_t)(int argc, char *argv[]);

#define CMD_BUFF_SIZE	100

static bool _ExitFlag = false;

static struct termios orig_term;

extern "C" {
	void _SigIntHandler(int sig_num);
	void _SigIntHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "Exiting..." << endl;
		cout.flush();
		_ExitFlag = true;
	}
	void _SigFpeHandler(int sig_num);
	void _SigFpeHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "floating point exception" << endl;
		PX4_BACKTRACE();
		cout.flush();
	}
}

static void print_prompt()
{
	cout.flush();
	cout << "pxh> ";
	cout.flush();
}

static void run_cmd(const vector<string> &appargs, bool exit_on_fail)
{
	// command is appargs[0]
	string command = appargs[0];

	if (apps.find(command) != apps.end()) {
		const char *arg[appargs.size() + 2];

		unsigned int i = 0;

		while (i < appargs.size() && appargs[i] != "") {
			arg[i] = (char *)appargs[i].c_str();
			++i;
		}

		arg[i] = (char *)0;

		cout << endl;

		int retval = apps[command](i, (char **)arg);

		if (retval) {
			cout << "Command '" << command << "' failed, returned " << retval << endl;

			if (exit_on_fail && retval) {
				exit(retval);
			}
		}

	} else if (command.compare("help") == 0) {
		list_builtins();

	} else if (command.length() == 0) {
		// Do nothing

	} else {
		cout << endl << "Invalid command: " << command << "\ntype 'help' for a list of commands" << endl;

	}
}

static void usage()
{

	cout << "./mainapp [-d] [startup_config] -h" << std::endl;
	cout << "   -d            - Optional flag to run the app in daemon mode and does not listen for user input." <<
	     std::endl;
	cout << "                   This is needed if mainapp is intended to be run as a upstart job on linux" << std::endl;
	cout << "<startup_config> - config file for starting/stopping px4 modules" << std::endl;
	cout << "   -h            - help/usage information" << std::endl;
}

static void process_line(string &line, bool exit_on_fail)
{
	if (line.length() == 0) {
		printf("\n");
	}

	vector<string> appargs(10);

	stringstream(line) >> appargs[0] >> appargs[1] >> appargs[2] >> appargs[3] >> appargs[4] >> appargs[5] >> appargs[6] >>
			   appargs[7] >> appargs[8] >> appargs[9];
	run_cmd(appargs, exit_on_fail);
}

static void restore_term(void)
{
	cout << "Restoring terminal\n";
	tcsetattr(0, TCSANOW, &orig_term);
}

bool px4_exit_requested(void) {
	return _ExitFlag;
}

int main(int argc, char **argv)
{
	bool daemon_mode = false;
	bool chroot_on = false;

	tcgetattr(0, &orig_term);
	atexit(restore_term);

	struct sigaction sig_int;
	memset(&sig_int, 0, sizeof(struct sigaction));
	sig_int.sa_handler = _SigIntHandler;
	sig_int.sa_flags = 0;// not SA_RESTART!;

	struct sigaction sig_fpe;
	memset(&sig_fpe, 0, sizeof(struct sigaction));
	sig_fpe.sa_handler = _SigFpeHandler;
	sig_fpe.sa_flags = 0;// not SA_RESTART!;

	sigaction(SIGINT, &sig_int, NULL);
	//sigaction(SIGTERM, &sig_int, NULL);
	sigaction(SIGFPE, &sig_fpe, NULL);

	int index = 1;
	char *commands_file = nullptr;

	while (index < argc) {
		if (argv[index][0] == '-') {
			// the arg starts with -
			if (strcmp(argv[index], "-d") == 0) {
				daemon_mode = true;

			} else if (strcmp(argv[index], "-h") == 0) {
				usage();
				return 0;

			} else if (strcmp(argv[index], "-c") == 0) {
				chroot_on = true;

			} else {
				PX4_WARN("Unknown/unhandled parameter: %s", argv[index]);
				return 1;
			}

		} else {
			// this is an argument that does not have '-' prefix; treat it like a file name
			ifstream infile(argv[index]);

			if (infile.good()) {
				infile.close();
				commands_file = argv[index];

			} else {
				PX4_WARN("Error opening file: %s", argv[index]);
				return -1;
			}
		}

		++index;
	}

	DriverFramework::Framework::initialize();
	px4::init_once();

	px4::init(argc, argv, "mainapp");

	// if commandfile is present, process the commands from the file
	if (commands_file != nullptr) {
		ifstream infile(commands_file);

		if (infile.is_open()) {
			for (string line; getline(infile, line, '\n');) {

				if (px4_exit_requested()) {
					break;
				}
				// TODO: this should be true but for that we have to check all startup files
				process_line(line, false);
			}

		} else {
			PX4_WARN("Error opening file: %s", commands_file);
		}
	}

	if (chroot_on) {
		// Lock this application in the current working dir
		// this is not an attempt to secure the environment,
		// rather, to replicate a deployed file system.

#ifdef PATH_MAX
		const unsigned path_max_len = PATH_MAX;
#else
		const unsigned path_max_len = 1024;
#endif

		char pwd_path[path_max_len];
		const char *folderpath = "/rootfs/";

		if (nullptr == getcwd(pwd_path, sizeof(pwd_path))) {
			PX4_ERR("Failed acquiring working dir, abort.");
			exit(1);
		}

		if (nullptr == strcat(pwd_path, folderpath)) {
			PX4_ERR("Failed completing path, abort.");
			exit(1);
		}

		if (chroot(pwd_path)) {
			PX4_ERR("Failed chrooting application, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}

		if (chdir("/")) {
			PX4_ERR("Failed changing to root dir, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}
	}

	if (!daemon_mode) {
		string mystr = "";
		string string_buffer[CMD_BUFF_SIZE];
		int buf_ptr_write = 0;
		int buf_ptr_read = 0;

		print_prompt();

		// change input mode so that we can manage shell
		struct termios term;
		tcgetattr(0, &term);
		term.c_lflag &= ~ICANON;
		term.c_lflag &= ~ECHO;
		tcsetattr(0, TCSANOW, &term);
		setbuf(stdin, NULL);

		while (!_ExitFlag) {

			char c = getchar();

			switch (c) {
			case 127:	// backslash
				if (mystr.length() > 0) {
					mystr.pop_back();
					printf("%c[2K", 27);	// clear line
					cout << (char)13;
					print_prompt();
					cout << mystr;
				}

				break;

			case'\n':	// user hit enter
				if (buf_ptr_write == CMD_BUFF_SIZE) {
					buf_ptr_write = 0;
				}

				if (buf_ptr_write > 0) {
					if (mystr != string_buffer[buf_ptr_write - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}

				} else {
					if (mystr != string_buffer[CMD_BUFF_SIZE - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}
				}

				process_line(mystr, false);
				mystr = "";
				buf_ptr_read = buf_ptr_write;

				print_prompt();
				break;

			case '\033': {	// arrow keys
					c = getchar();	// skip first one, does not have the info
					c = getchar();

					// arrow up
					if (c == 'A') {
						buf_ptr_read--;
						// arrow down

					} else if (c == 'B') {
						if (buf_ptr_read < buf_ptr_write) {
							buf_ptr_read++;
						}

					} else {
						// TODO: Support editing current line
					}

					if (buf_ptr_read < 0) {
						buf_ptr_read = 0;
					}

					string saved_cmd = string_buffer[buf_ptr_read];
					printf("%c[2K", 27);
					cout << (char)13;
					mystr = saved_cmd;
					print_prompt();
					cout << mystr;
					break;
				}

			default:	// any other input
				cout << c;
				mystr += c;
				break;
			}
		}

	} else {
		while (!_ExitFlag) {
			usleep(100000);
		}
	}

	// TODO: Always try to stop muorb for QURT because px4_task_is_running doesn't seem to work.
	if (true) {
		//if (px4_task_is_running("muorb")) {
		// sending muorb stop is needed if it is running to exit cleanly
		vector<string> muorb_stop_cmd = { "muorb", "stop" };
		run_cmd(muorb_stop_cmd, !daemon_mode);
	}

	vector<string> shutdown_cmd = { "shutdown" };
	run_cmd(shutdown_cmd, true);
	DriverFramework::Framework::shutdown();

	return OK;
}
<commit_msg>POSIX: Fix code style of main app<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/
/**
 * @file main.cpp
 * Basic shell to execute builtin "apps"
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 * @author Roman Bapst <bapstroman@gmail.com>
 */

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include "apps.h"
#include "px4_middleware.h"
#include "DriverFramework.hpp"
#include <termios.h>

namespace px4
{
void init_once(void);
}

using namespace std;

typedef int (*px4_main_t)(int argc, char *argv[]);

#define CMD_BUFF_SIZE	100

static bool _ExitFlag = false;

static struct termios orig_term;

extern "C" {
	void _SigIntHandler(int sig_num);
	void _SigIntHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "Exiting..." << endl;
		cout.flush();
		_ExitFlag = true;
	}
	void _SigFpeHandler(int sig_num);
	void _SigFpeHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "floating point exception" << endl;
		PX4_BACKTRACE();
		cout.flush();
	}
}

static void print_prompt()
{
	cout.flush();
	cout << "pxh> ";
	cout.flush();
}

static void run_cmd(const vector<string> &appargs, bool exit_on_fail)
{
	// command is appargs[0]
	string command = appargs[0];

	if (apps.find(command) != apps.end()) {
		const char *arg[appargs.size() + 2];

		unsigned int i = 0;

		while (i < appargs.size() && appargs[i] != "") {
			arg[i] = (char *)appargs[i].c_str();
			++i;
		}

		arg[i] = (char *)0;

		cout << endl;

		int retval = apps[command](i, (char **)arg);

		if (retval) {
			cout << "Command '" << command << "' failed, returned " << retval << endl;

			if (exit_on_fail && retval) {
				exit(retval);
			}
		}

	} else if (command.compare("help") == 0) {
		list_builtins();

	} else if (command.length() == 0) {
		// Do nothing

	} else {
		cout << endl << "Invalid command: " << command << "\ntype 'help' for a list of commands" << endl;

	}
}

static void usage()
{

	cout << "./mainapp [-d] [startup_config] -h" << std::endl;
	cout << "   -d            - Optional flag to run the app in daemon mode and does not listen for user input." <<
	     std::endl;
	cout << "                   This is needed if mainapp is intended to be run as a upstart job on linux" << std::endl;
	cout << "<startup_config> - config file for starting/stopping px4 modules" << std::endl;
	cout << "   -h            - help/usage information" << std::endl;
}

static void process_line(string &line, bool exit_on_fail)
{
	if (line.length() == 0) {
		printf("\n");
	}

	vector<string> appargs(10);

	stringstream(line) >> appargs[0] >> appargs[1] >> appargs[2] >> appargs[3] >> appargs[4] >> appargs[5] >> appargs[6] >>
			   appargs[7] >> appargs[8] >> appargs[9];
	run_cmd(appargs, exit_on_fail);
}

static void restore_term(void)
{
	cout << "Restoring terminal\n";
	tcsetattr(0, TCSANOW, &orig_term);
}

bool px4_exit_requested(void)
{
	return _ExitFlag;
}

int main(int argc, char **argv)
{
	bool daemon_mode = false;
	bool chroot_on = false;

	tcgetattr(0, &orig_term);
	atexit(restore_term);

	struct sigaction sig_int;
	memset(&sig_int, 0, sizeof(struct sigaction));
	sig_int.sa_handler = _SigIntHandler;
	sig_int.sa_flags = 0;// not SA_RESTART!;

	struct sigaction sig_fpe;
	memset(&sig_fpe, 0, sizeof(struct sigaction));
	sig_fpe.sa_handler = _SigFpeHandler;
	sig_fpe.sa_flags = 0;// not SA_RESTART!;

	sigaction(SIGINT, &sig_int, NULL);
	//sigaction(SIGTERM, &sig_int, NULL);
	sigaction(SIGFPE, &sig_fpe, NULL);

	int index = 1;
	char *commands_file = nullptr;

	while (index < argc) {
		if (argv[index][0] == '-') {
			// the arg starts with -
			if (strcmp(argv[index], "-d") == 0) {
				daemon_mode = true;

			} else if (strcmp(argv[index], "-h") == 0) {
				usage();
				return 0;

			} else if (strcmp(argv[index], "-c") == 0) {
				chroot_on = true;

			} else {
				PX4_WARN("Unknown/unhandled parameter: %s", argv[index]);
				return 1;
			}

		} else {
			// this is an argument that does not have '-' prefix; treat it like a file name
			ifstream infile(argv[index]);

			if (infile.good()) {
				infile.close();
				commands_file = argv[index];

			} else {
				PX4_WARN("Error opening file: %s", argv[index]);
				return -1;
			}
		}

		++index;
	}

	DriverFramework::Framework::initialize();
	px4::init_once();

	px4::init(argc, argv, "mainapp");

	// if commandfile is present, process the commands from the file
	if (commands_file != nullptr) {
		ifstream infile(commands_file);

		if (infile.is_open()) {
			for (string line; getline(infile, line, '\n');) {

				if (px4_exit_requested()) {
					break;
				}

				// TODO: this should be true but for that we have to check all startup files
				process_line(line, false);
			}

		} else {
			PX4_WARN("Error opening file: %s", commands_file);
		}
	}

	if (chroot_on) {
		// Lock this application in the current working dir
		// this is not an attempt to secure the environment,
		// rather, to replicate a deployed file system.

#ifdef PATH_MAX
		const unsigned path_max_len = PATH_MAX;
#else
		const unsigned path_max_len = 1024;
#endif

		char pwd_path[path_max_len];
		const char *folderpath = "/rootfs/";

		if (nullptr == getcwd(pwd_path, sizeof(pwd_path))) {
			PX4_ERR("Failed acquiring working dir, abort.");
			exit(1);
		}

		if (nullptr == strcat(pwd_path, folderpath)) {
			PX4_ERR("Failed completing path, abort.");
			exit(1);
		}

		if (chroot(pwd_path)) {
			PX4_ERR("Failed chrooting application, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}

		if (chdir("/")) {
			PX4_ERR("Failed changing to root dir, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}
	}

	if (!daemon_mode) {
		string mystr = "";
		string string_buffer[CMD_BUFF_SIZE];
		int buf_ptr_write = 0;
		int buf_ptr_read = 0;

		print_prompt();

		// change input mode so that we can manage shell
		struct termios term;
		tcgetattr(0, &term);
		term.c_lflag &= ~ICANON;
		term.c_lflag &= ~ECHO;
		tcsetattr(0, TCSANOW, &term);
		setbuf(stdin, NULL);

		while (!_ExitFlag) {

			char c = getchar();

			switch (c) {
			case 127:	// backslash
				if (mystr.length() > 0) {
					mystr.pop_back();
					printf("%c[2K", 27);	// clear line
					cout << (char)13;
					print_prompt();
					cout << mystr;
				}

				break;

			case'\n':	// user hit enter
				if (buf_ptr_write == CMD_BUFF_SIZE) {
					buf_ptr_write = 0;
				}

				if (buf_ptr_write > 0) {
					if (mystr != string_buffer[buf_ptr_write - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}

				} else {
					if (mystr != string_buffer[CMD_BUFF_SIZE - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}
				}

				process_line(mystr, false);
				mystr = "";
				buf_ptr_read = buf_ptr_write;

				print_prompt();
				break;

			case '\033': {	// arrow keys
					c = getchar();	// skip first one, does not have the info
					c = getchar();

					// arrow up
					if (c == 'A') {
						buf_ptr_read--;
						// arrow down

					} else if (c == 'B') {
						if (buf_ptr_read < buf_ptr_write) {
							buf_ptr_read++;
						}

					} else {
						// TODO: Support editing current line
					}

					if (buf_ptr_read < 0) {
						buf_ptr_read = 0;
					}

					string saved_cmd = string_buffer[buf_ptr_read];
					printf("%c[2K", 27);
					cout << (char)13;
					mystr = saved_cmd;
					print_prompt();
					cout << mystr;
					break;
				}

			default:	// any other input
				cout << c;
				mystr += c;
				break;
			}
		}

	} else {
		while (!_ExitFlag) {
			usleep(100000);
		}
	}

	// TODO: Always try to stop muorb for QURT because px4_task_is_running doesn't seem to work.
	if (true) {
		//if (px4_task_is_running("muorb")) {
		// sending muorb stop is needed if it is running to exit cleanly
		vector<string> muorb_stop_cmd = { "muorb", "stop" };
		run_cmd(muorb_stop_cmd, !daemon_mode);
	}

	vector<string> shutdown_cmd = { "shutdown" };
	run_cmd(shutdown_cmd, true);
	DriverFramework::Framework::shutdown();

	return OK;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/** \file xc_functional.hpp
 *
 *  \brief Contains implementation of sirius::XC_functional class.
 */

#ifndef __XC_FUNCTIONAL_HPP__
#define __XC_FUNCTIONAL_HPP__

#include <xc.h>
#include <string.h>
#include "xc_functional_base.hpp"
#include "SDDK/fft3d.hpp"
#ifdef USE_VDWXC
#include <vdwxc.h>
#include <vdwxc_mpi.h>
#endif

namespace sirius {

/// Interface class to Libxc.
    class XC_functional : public XC_functional_base
{
    private:
        // I can not use a generic void pointer because xc_func_type is a structure
        // while wdv_functional_ is a pointer over structure.
#ifdef USE_VDWXC
        vdwxc_data handler_vdw_{nullptr};
        bool vdw_functional_{false};
#endif
        /* forbid copy constructor */
        XC_functional(const XC_functional& src) = delete;

        /* forbid assigment operator */
        XC_functional& operator=(const XC_functional& src) = delete;

    public:
    /* we need the context because libvdwxc asks for lattice vectors and fft parameters */

    XC_functional(const FFT3D& fft, const matrix3d<double>& lattice_vectors_, const std::string libxc_name__, int num_spins__)
        :  XC_functional_base(libxc_name__, num_spins__)
        {

#ifdef USE_VDWXC
            /* return immediately if the functional_base class is initialized */
            if (this->libxc_initialized_) {
                return;
            }

            /* test if have van der walls functionals types */

            bool test = (libxc_name_ == "XC_FUNC_VDWDF");
            test = test || (libxc_name_ == "XC_FUNC_VDWDF2");
            test = test || (libxc_name_ == "XC_FUNC_VDWDFCX");

            int func_ = -1;

            if (libxc_name__ == "XC_FUNC_VDWDF") {
                func_ = FUNC_VDWDF;
            }

            if (libxc_name__ == "XC_FUNC_VDWDF2") {
                func_ = FUNC_VDWDF2;
            }

            if (libxc_name__ == "XC_FUNC_VDWDFCX") {
                func_ = FUNC_VDWDFCX;
            }

            if (test) {
                if (num_spins__ == 1) {
                    // non magnetic case
                    handler_vdw_ = vdwxc_new(func_);
                } else {
                    // magnetic case
                    handler_vdw_ = vdwxc_new_spin(func_);
                }

                if (!handler_vdw_) {
                    std::stringstream s;
                    s << "VDW functional lib could not be initialized";
                    TERMINATE(s);
                }

                double v1[3] = { lattice_vectors_(0, 0), lattice_vectors_(1, 0), lattice_vectors_(2, 0) };
                double v2[3] = { lattice_vectors_(0, 1), lattice_vectors_(1, 1), lattice_vectors_(2, 1) };
                double v3[3] = { lattice_vectors_(0, 2), lattice_vectors_(1, 2), lattice_vectors_(2, 2) };
                vdwxc_set_unit_cell(handler_vdw_,
                                    fft.size(0),
                                    fft.size(1),
                                    fft.size(2),
                                    v1[0], v1[1], v1[2],
                                    v2[0], v2[1], v2[2],
                                    v3[0], v3[1], v3[2]);

                if (fft.comm().size() == 1) {
                    vdwxc_init_serial(handler_vdw_);
                } else {
                    vdwxc_init_mpi(handler_vdw_, fft.comm().mpi_comm());
                }
                vdw_functional_ = true;
                return;
            } else {
                /* it means that the functional does not exist either in vdw or xc libraries */
                std::stringstream s;
                s << "XC functional " << libxc_name__ << " is unknown";
                TERMINATE(s);
            }
#else
            if (this->libxc_initialized_) {
                return;
            } else {
                /* it means that the functional does not exist either in vdw or xc libraries */
                std::stringstream s;
                s << "XC functional " << libxc_name__ << " is unknown";
                TERMINATE(s);
            }
#endif /* USE_VDWXC */
        }

    XC_functional(XC_functional&& src__)
        :XC_functional_base(std::move(src__))
        {
#ifdef USE_VDWXC
            this->handler_vdw_ = src__.handler_vdw_;
            this->vdw_functional_ = src__.vdw_functional_;
            src__.vdw_functional_ = false;
#endif
        }

    ~XC_functional()
        {
#ifdef USE_VDWXC
            if (this->vdw_functional_) {
                vdwxc_finalize(&this->handler_vdw_);
                this->vdw_functional_ = false;
                return;
            }
#endif
        }

        const std::string refs() const
        {
#ifdef USE_VDWXC
            std::stringstream s;
            if (vdw_functional_) {
                s << "==============================================================================\n";
                s << "                                                                              \n";
                s << "Warning : these functionals should be used in combination with GGA functionals\n";
                s << "                                                                              \n";
                s << "==============================================================================\n";
                s << "\n";
                s << "A. H. Larsen, M. Kuisma, J. Löfgren, Y. Pouillon, P. Erhart, and P. Hyldgaard, ";
                s << "Modelling Simul. Mater. Sci. Eng. 25, 065004 (2017) (10.1088/1361-651X/aa7320)\n";
                return s.str();
            }
#endif
            return XC_functional_base::refs();
        }

        int family() const
        {
#ifdef USE_VDWXC
            if (this->vdw_functional_ == true) {
                return XC_FAMILY_UNKNOWN;
            }
#endif
            return XC_functional_base::family();
        }

        bool is_vdw() const
        {
#ifdef USE_VDWXC
            return this->vdw_functional_;
#else
            return false;
#endif
        }
        int kind() const
        {

#ifdef USE_VDWXC
            if (this->vdw_functional_ == true) {
                return -1;
            }
#endif
            return XC_functional_base::kind();
        }

#ifdef USE_VDWXC
    /// get van der walls contribution for the exchange term
    void get_vdw(double* rho,
                 double* sigma,
                 double* vrho,
                 double* vsigma,
                 double* energy__)
        {
            if (!is_vdw()) {
                TERMINATE("Error wrong vdw XC");
            }
            energy__[0] = vdwxc_calculate(handler_vdw_, rho, sigma, vrho, vsigma);
        }

    /// get van der walls contribution to the exchange term magnetic case
    void get_vdw(double *rho_up, double *rho_down,
                 double *sigma_up, double *sigma_down,
                 double *vrho_up, double *vrho_down,
                 double *vsigma_up, double *vsigma_down,
                 double *energy__)
        {
            if (!is_vdw()) {
                TERMINATE("Error wrong XC");
            }

            energy__[0] = vdwxc_calculate_spin(handler_vdw_, rho_up, rho_down,
                                               sigma_up , sigma_down,
                                               vrho_up, vrho_down,
                                               vsigma_up, vsigma_down);
        }
#endif
};

}

#endif // __XC_FUNCTIONAL_H__
<commit_msg>fallback to serial if libvdwxc has not been compiled with MPI<commit_after>// Copyright (c) 2013-2016 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/** \file xc_functional.hpp
 *
 *  \brief Contains implementation of sirius::XC_functional class.
 */

#ifndef __XC_FUNCTIONAL_HPP__
#define __XC_FUNCTIONAL_HPP__

#include <xc.h>
#include <string.h>
#include "xc_functional_base.hpp"
#include "SDDK/fft3d.hpp"
#ifdef USE_VDWXC
#include <vdwxc.h>
#if VDWXC_FFTW_MPI == 1
#include <vdwxc_mpi.h>
#endif
#endif

namespace sirius {

/// Interface class to Libxc.
    class XC_functional : public XC_functional_base
{
    private:
        // I can not use a generic void pointer because xc_func_type is a structure
        // while wdv_functional_ is a pointer over structure.
#ifdef USE_VDWXC
        vdwxc_data handler_vdw_{nullptr};
        bool vdw_functional_{false};
#endif
        /* forbid copy constructor */
        XC_functional(const XC_functional& src) = delete;

        /* forbid assigment operator */
        XC_functional& operator=(const XC_functional& src) = delete;

    public:
    /* we need the context because libvdwxc asks for lattice vectors and fft parameters */

    XC_functional(const FFT3D& fft, const matrix3d<double>& lattice_vectors_, const std::string libxc_name__, int num_spins__)
        :  XC_functional_base(libxc_name__, num_spins__)
        {

#ifdef USE_VDWXC
            /* return immediately if the functional_base class is initialized */
            if (this->libxc_initialized_) {
                return;
            }

            /* test if have van der walls functionals types */

            bool test = (libxc_name_ == "XC_FUNC_VDWDF");
            test = test || (libxc_name_ == "XC_FUNC_VDWDF2");
            test = test || (libxc_name_ == "XC_FUNC_VDWDFCX");

            int func_ = -1;

            if (libxc_name__ == "XC_FUNC_VDWDF") {
                func_ = FUNC_VDWDF;
            }

            if (libxc_name__ == "XC_FUNC_VDWDF2") {
                func_ = FUNC_VDWDF2;
            }

            if (libxc_name__ == "XC_FUNC_VDWDFCX") {
                func_ = FUNC_VDWDFCX;
            }

            if (test) {
                if (num_spins__ == 1) {
                    // non magnetic case
                    handler_vdw_ = vdwxc_new(func_);
                } else {
                    // magnetic case
                    handler_vdw_ = vdwxc_new_spin(func_);
                }

                if (!handler_vdw_) {
                    std::stringstream s;
                    s << "VDW functional lib could not be initialized";
                    TERMINATE(s);
                }

                double v1[3] = { lattice_vectors_(0, 0), lattice_vectors_(1, 0), lattice_vectors_(2, 0) };
                double v2[3] = { lattice_vectors_(0, 1), lattice_vectors_(1, 1), lattice_vectors_(2, 1) };
                double v3[3] = { lattice_vectors_(0, 2), lattice_vectors_(1, 2), lattice_vectors_(2, 2) };
                vdwxc_set_unit_cell(handler_vdw_,
                                    fft.size(0),
                                    fft.size(1),
                                    fft.size(2),
                                    v1[0], v1[1], v1[2],
                                    v2[0], v2[1], v2[2],
                                    v3[0], v3[1], v3[2]);

                if (fft.comm().size() == 1) {
                    vdwxc_init_serial(handler_vdw_);
                } else {
#if VDWXC_FFTW_MPI == 1
                    vdwxc_init_mpi(handler_vdw_, fft.comm().mpi_comm());
#else
                    vdwxc_init_serial(handler_vdw_);
#endif
                }
                vdw_functional_ = true;
                return;
            } else {
                /* it means that the functional does not exist either in vdw or xc libraries */
                std::stringstream s;
                s << "XC functional " << libxc_name__ << " is unknown";
                TERMINATE(s);
            }
#else
            if (this->libxc_initialized_) {
                return;
            } else {
                /* it means that the functional does not exist either in vdw or xc libraries */
                std::stringstream s;
                s << "XC functional " << libxc_name__ << " is unknown";
                TERMINATE(s);
            }
#endif /* USE_VDWXC */
        }

    XC_functional(XC_functional&& src__)
        :XC_functional_base(std::move(src__))
        {
#ifdef USE_VDWXC
            this->handler_vdw_ = src__.handler_vdw_;
            this->vdw_functional_ = src__.vdw_functional_;
            src__.vdw_functional_ = false;
#endif
        }

    ~XC_functional()
        {
#ifdef USE_VDWXC
            if (this->vdw_functional_) {
                vdwxc_finalize(&this->handler_vdw_);
                this->vdw_functional_ = false;
                return;
            }
#endif
        }

        const std::string refs() const
        {
#ifdef USE_VDWXC
            std::stringstream s;
            if (vdw_functional_) {
                s << "==============================================================================\n";
                s << "                                                                              \n";
                s << "Warning : these functionals should be used in combination with GGA functionals\n";
                s << "                                                                              \n";
                s << "==============================================================================\n";
                s << "\n";
                s << "A. H. Larsen, M. Kuisma, J. Löfgren, Y. Pouillon, P. Erhart, and P. Hyldgaard, ";
                s << "Modelling Simul. Mater. Sci. Eng. 25, 065004 (2017) (10.1088/1361-651X/aa7320)\n";
                return s.str();
            }
#endif
            return XC_functional_base::refs();
        }

        int family() const
        {
#ifdef USE_VDWXC
            if (this->vdw_functional_ == true) {
                return XC_FAMILY_UNKNOWN;
            }
#endif
            return XC_functional_base::family();
        }

        bool is_vdw() const
        {
#ifdef USE_VDWXC
            return this->vdw_functional_;
#else
            return false;
#endif
        }
        int kind() const
        {

#ifdef USE_VDWXC
            if (this->vdw_functional_ == true) {
                return -1;
            }
#endif
            return XC_functional_base::kind();
        }

#ifdef USE_VDWXC
    /// get van der walls contribution for the exchange term
    void get_vdw(double* rho,
                 double* sigma,
                 double* vrho,
                 double* vsigma,
                 double* energy__)
        {
            if (!is_vdw()) {
                TERMINATE("Error wrong vdw XC");
            }
            energy__[0] = vdwxc_calculate(handler_vdw_, rho, sigma, vrho, vsigma);
        }

    /// get van der walls contribution to the exchange term magnetic case
    void get_vdw(double *rho_up, double *rho_down,
                 double *sigma_up, double *sigma_down,
                 double *vrho_up, double *vrho_down,
                 double *vsigma_up, double *vsigma_down,
                 double *energy__)
        {
            if (!is_vdw()) {
                TERMINATE("Error wrong XC");
            }

            energy__[0] = vdwxc_calculate_spin(handler_vdw_, rho_up, rho_down,
                                               sigma_up , sigma_down,
                                               vrho_up, vrho_down,
                                               vsigma_up, vsigma_down);
        }
#endif
};

}

#endif // __XC_FUNCTIONAL_H__
<|endoftext|>


<commit_before>/* Copyright (c) 2013 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any purpose
 * with or without fee is hereby granted, provided that the above copyright
 * notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Common.h"
#include "ExternalStorage.h"

namespace RAMCloud {

/**
 * Constructor for ExternalStorage objects.
 */
ExternalStorage::ExternalStorage()
    : workspace("/")
    , fullName(workspace)
    , testName(NULL)
{}

// See header file for documentation.
const char*
ExternalStorage::getWorkspace()
{
    return workspace.c_str();
}

// See header file for documentation.
void
ExternalStorage::setWorkspace(const char* pathPrefix)
{
    workspace = pathPrefix;
    fullName = pathPrefix;
    assert(pathPrefix[0] == '/');
    assert(pathPrefix[workspace.size()-1] == '/');
}

/**
 * Return the absolute node name (i.e., one that begins with "/") that
 * corresponds to the \c name argument. It is provided as a convenience for
 * subclasses.
 *
 * \param name
 *      Name of a node; may be either relative or absolute.
 *
 * \return
 *      If \c name starts with "/", then it is returned. Otherwise, an
 *      absolute node name is formed by concatenating the workspace name
 *      with \c name, and this is returned. Note: the return value is stored
 *      in a string in the ExternalStorage object, and will be overwritten
 *      the next time this method is invoked. If you need the result to
 *      last a long time, you better copy it. This method is not thread-safe:
 *      it assumes the caller has acquired a lock, so that no one else can
 *      invoke this method concurrently.
 */
const char*
ExternalStorage::getFullName(const char* name)
{
    if (testName != NULL) {
        return testName;
    }
    if (name[0] == '/') {
        return name;
    }
    fullName.resize(workspace.size());
    fullName.append(name);
    return fullName.c_str();
}

/**
 * Construct an Object.
 *
 * \param name
 *      Name of the object; NULL-terminated string. A local copy will
 *      be made in this Object.
 * \param value
 *      Value of the object, or NULL if none. A local copy will
 *      be made in this Object.
 * \param length
 *      Length of value, in bytes.
 */
ExternalStorage::Object::Object(const char* name, const char* value, int length)
    : name(NULL)
    , value(NULL)
    , length(0)
{
    size_t nameLength = strlen(name) + 1;
    this->name = static_cast<char*>(malloc(nameLength));
    memcpy(this->name, name, nameLength);
    if ((value != NULL) && (length > 0)) {
        this->value = static_cast<char*>(malloc(length));
        memcpy(this->value, value, length);
        this->length = length;
    }
}

/**
 * Destructor for Objects (must free storage).
 */
ExternalStorage::Object::~Object()
{
    free(name);
    free(value);
}

} // namespace RAMCloud
<commit_msg>Fixed lint from "make check".<commit_after>/* Copyright (c) 2013 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any purpose
 * with or without fee is hereby granted, provided that the above copyright
 * notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Common.h"
#include "ExternalStorage.h"

namespace RAMCloud {

/**
 * Constructor for ExternalStorage objects.
 */
ExternalStorage::ExternalStorage()
    : workspace("/")
    , fullName(workspace)
    , testName(NULL)
{}

// See header file for documentation.
const char*
ExternalStorage::getWorkspace()
{
    return workspace.c_str();
}

// See header file for documentation.
void
ExternalStorage::setWorkspace(const char* pathPrefix)
{
    workspace = pathPrefix;
    fullName = pathPrefix;
    assert(pathPrefix[0] == '/');
    assert(pathPrefix[workspace.size()-1] == '/');
}

/**
 * Return the absolute node name (i.e., one that begins with "/") that
 * corresponds to the \c name argument. It is provided as a convenience for
 * subclasses.
 *
 * \param name
 *      Name of a node; may be either relative or absolute.
 *
 * \return
 *      If \c name starts with "/", then it is returned. Otherwise, an
 *      absolute node name is formed by concatenating the workspace name
 *      with \c name, and this is returned. Note: the return value is stored
 *      in a string in the ExternalStorage object, and will be overwritten
 *      the next time this method is invoked. If you need the result to
 *      last a long time, you better copy it. This method is not thread-safe:
 *      it assumes the caller has acquired a lock, so that no one else can
 *      invoke this method concurrently.
 */
const char*
ExternalStorage::getFullName(const char* name)
{
    if (testName != NULL) {
        return testName;
    }
    if (name[0] == '/') {
        return name;
    }
    fullName.resize(workspace.size());
    fullName.append(name);
    return fullName.c_str();
}

/**
 * Construct an Object.
 *
 * \param name
 *      Name of the object; NULL-terminated string. A local copy will
 *      be made in this Object.
 * \param value
 *      Value of the object, or NULL if none. A local copy will
 *      be made in this Object.
 * \param length
 *      Length of value, in bytes.
 */
ExternalStorage::Object::Object(const char* name, const char* value, int length)
    : name(NULL)
    , value(NULL)
    , length(0)
{
    size_t nameLength = strlen(name) + 1;
    this->name = static_cast<char*>(malloc(nameLength));
    memcpy(this->name, name, nameLength);
    if ((value != NULL) && (length > 0)) {
        this->value = static_cast<char*>(malloc(length));
        memcpy(this->value, value, length);
        this->length = length;
    }
}

/**
 * Destructor for Objects (must free storage).
 */
ExternalStorage::Object::~Object()
{
    free(name);
    free(value);
}

} // namespace RAMCloud
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Rüdiger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_PLUGINS_GMP_RATIONAL_HPP
#define FLUSSPFERD_PLUGINS_GMP_RATIONAL_HPP

#include "flusspferd/class.hpp"
#include "flusspferd/create.hpp"
#include <gmpxx.h>

//#include "Integer.hpp"

namespace multi_precission {
class Integer;

struct Rational : public flusspferd::native_object_base {
  struct class_info : flusspferd::class_info {
    static char const *constructor_name() {
      return "Rational";
    }

    static char const *full_name() {
      return "Rational";
    }

    static object create_prototype() {
      flusspferd::object proto = flusspferd::create_object();
      create_native_method(proto, "get_double", &Rational::get_double);
      create_native_method(proto, "get_string", &Rational::get_string);
      create_native_method(proto, "get_string_base", &Rational::get_string_base);
      create_native_method(proto, "sgn", &Rational::sgn);
      create_native_method(proto, "abs", &Rational::abs);
      create_native_method(proto, "canonicalize", &Rational::canonicalize);
      create_native_method(proto, "get_num", &Rational::get_num);
      create_native_method(proto, "get_den", &Rational::get_den);
      create_native_method(proto, "cmp", &Rational::cmp);
      create_native_method(proto, "add", &Rational::add);
      create_native_method(proto, "sub", &Rational::sub);
      create_native_method(proto, "mul", &Rational::mul);
      create_native_method(proto, "div", &Rational::div);
      return proto;
    }
  };
  mpq_class mp;

  Rational(flusspferd::object const &self, mpq_class const &mp);
  Rational(flusspferd::object const &self, flusspferd::call_context &x);

  double get_double() /*const*/;
  std::string get_string() /*const*/;
  std::string get_string_base(int base) /*const*/;

  template<typename T>
  static Rational &create_rational(T mp) {
    return flusspferd::create_native_object<Rational>(object(), mpq_class(mp));
  }

  int sgn() /*const*/;
  Rational &abs() /*const*/;
  void canonicalize();

  Integer &get_num() /*const*/;
  Integer &get_den() /*const*/;

  // operators
  void cmp(flusspferd::call_context &x) /*const*/;

  void add(flusspferd::call_context &x) /*const*/;
  void sub(flusspferd::call_context &x) /*const*/;
  void mul(flusspferd::call_context &x) /*const*/;
  void div(flusspferd::call_context &x) /*const*/;
};
}

#endif
<commit_msg>plugins.gmp: minor cleanup<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Rüdiger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_PLUGINS_GMP_RATIONAL_HPP
#define FLUSSPFERD_PLUGINS_GMP_RATIONAL_HPP

#include "flusspferd/class.hpp"
#include "flusspferd/create.hpp"
#include <gmpxx.h>

namespace multi_precission {
class Integer;

struct Rational : public flusspferd::native_object_base {
  struct class_info : flusspferd::class_info {
    static char const *constructor_name() {
      return "Rational";
    }

    static char const *full_name() {
      return "Rational";
    }

    static object create_prototype() {
      flusspferd::object proto = flusspferd::create_object();
      create_native_method(proto, "get_double", &Rational::get_double);
      create_native_method(proto, "get_string", &Rational::get_string);
      create_native_method(proto, "get_string_base", &Rational::get_string_base);
      create_native_method(proto, "sgn", &Rational::sgn);
      create_native_method(proto, "abs", &Rational::abs);
      create_native_method(proto, "canonicalize", &Rational::canonicalize);
      create_native_method(proto, "get_num", &Rational::get_num);
      create_native_method(proto, "get_den", &Rational::get_den);
      create_native_method(proto, "cmp", &Rational::cmp);
      create_native_method(proto, "add", &Rational::add);
      create_native_method(proto, "sub", &Rational::sub);
      create_native_method(proto, "mul", &Rational::mul);
      create_native_method(proto, "div", &Rational::div);
      return proto;
    }
  };
  mpq_class mp;

  Rational(flusspferd::object const &self, mpq_class const &mp);
  Rational(flusspferd::object const &self, flusspferd::call_context &x);

  double get_double() /*const*/;
  std::string get_string() /*const*/;
  std::string get_string_base(int base) /*const*/;

  template<typename T>
  static Rational &create_rational(T mp) {
    return flusspferd::create_native_object<Rational>(object(), mpq_class(mp));
  }

  int sgn() /*const*/;
  Rational &abs() /*const*/;
  void canonicalize();

  Integer &get_num() /*const*/;
  Integer &get_den() /*const*/;

  // operators
  void cmp(flusspferd::call_context &x) /*const*/;

  void add(flusspferd::call_context &x) /*const*/;
  void sub(flusspferd::call_context &x) /*const*/;
  void mul(flusspferd::call_context &x) /*const*/;
  void div(flusspferd::call_context &x) /*const*/;
};
}

#endif
<|endoftext|>


<commit_before>//===--- GenTypes.cpp - Swift IR Generation For Types ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements IR generation for types in Swift.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/Decl.h"
#include "swift/AST/Types.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetData.h"

#include "GenType.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "Address.h"
#include "Explosion.h"
#include "Linking.h"

using namespace swift;
using namespace irgen;

bool TypeInfo::isSingleRetainablePointer(ResilienceScope scope) const {
  return false;
}

ExplosionSchema TypeInfo::getSchema(ExplosionKind kind) const {
  ExplosionSchema schema(kind);
  getSchema(schema);
  return schema;
}

/// Copy a value from one object to a new object, directly taking
/// responsibility for anything it might have.  This is like C++
/// move-initialization, except the old object will not be destroyed.
void TypeInfo::initializeWithTake(IRGenFunction &IGF,
                                  Address destAddr, Address srcAddr) const {
  // Prefer loads and stores if we won't make a million of them.
  // Maybe this should also require the scalars to have a fixed offset.
  ExplosionSchema schema = getSchema(ExplosionKind::Maximal);
  if (!schema.containsAggregate() && schema.size() <= 2) {
    Explosion copy(ExplosionKind::Maximal);
    load(IGF, srcAddr, copy);
    initialize(IGF, copy, destAddr);
    return;
  }

  // Otherwise, use a memcpy.
  IGF.emitMemCpy(destAddr.getAddress(), srcAddr.getAddress(),
                 StorageSize, std::min(destAddr.getAlignment(),
                                       srcAddr.getAlignment()));
}

static TypeInfo *invalidTypeInfo() { return (TypeInfo*) 1; }

namespace {
  /// Basic IR generation for primitive types, which are always
  /// represented as a single scalar.
  class PrimitiveTypeInfo : public TypeInfo {
  public:
    PrimitiveTypeInfo(llvm::Type *Type, Size S, Alignment A)
      : TypeInfo(Type, S, A) {}

    unsigned getExplosionSize(ExplosionKind kind) const {
      return 1;
    }

    void getSchema(ExplosionSchema &schema) const {
      schema.add(ExplosionSchema::Element::forScalar(getStorageType()));
    }

    void load(IRGenFunction &IGF, Address addr, Explosion &e) const {
      e.addUnmanaged(IGF.Builder.CreateLoad(addr));
    }

    void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
      IGF.Builder.CreateStore(e.claimUnmanagedNext(), addr);
    }

    void initialize(IRGenFunction &IGF, Explosion &e, Address addr) const {
      IGF.Builder.CreateStore(e.claimUnmanagedNext(), addr);
    }

    void reexplode(IRGenFunction &IGF, Explosion &src, Explosion &dest) const {
      src.transferInto(dest, 1);
    }

    void manage(IRGenFunction &IGF, Explosion &src, Explosion &dest) const {
      src.transferInto(dest, 1);
    }
  };
}

/// Constructs a type info which performs simple loads and stores of
/// the given IR type.
const TypeInfo *TypeConverter::createPrimitive(llvm::Type *type,
                                               Size size, Alignment align) {
  return new PrimitiveTypeInfo(type, size, align);
}

TypeConverter::TypeConverter() : FirstConverted(invalidTypeInfo()) {}

TypeConverter::~TypeConverter() {
  // Delete all the converted type infos.
  for (const TypeInfo *I = FirstConverted; I != invalidTypeInfo(); ) {
    const TypeInfo *Cur = I;
    I = Cur->NextConverted;
    delete Cur;
  }
}

/// Get the fragile type information for the given type.
const TypeInfo &IRGenFunction::getFragileTypeInfo(Type T) {
  return IGM.getFragileTypeInfo(T);
}

/// Get the fragile IR type for the given type.
llvm::Type *IRGenModule::getFragileType(Type T) {
  return getFragileTypeInfo(T).StorageType;
}

/// Get the fragile type information for the given type.
const TypeInfo &IRGenModule::getFragileTypeInfo(Type T) {
  return TypeConverter::getFragileTypeInfo(*this, T);
}

const TypeInfo &TypeConverter::getFragileTypeInfo(IRGenModule &IGM, Type T) {
  assert(!T.isNull());
  auto Entry = IGM.Types.Converted.find(T.getPointer());
  if (Entry != IGM.Types.Converted.end())
    return *Entry->second;

  const TypeInfo *Result = convertType(IGM, T);
  IGM.Types.Converted[T.getPointer()] = Result;

  // If the type info hasn't been added to the list of types, do so.
  if (!Result->NextConverted) {
    Result->NextConverted = IGM.Types.FirstConverted;
    IGM.Types.FirstConverted = Result;
  }

  return *Result;
}

const TypeInfo *TypeConverter::convertType(IRGenModule &IGM, Type T) {
  llvm::LLVMContext &Ctx = IGM.getLLVMContext();
  TypeBase *TB = T.getPointer();
  switch (TB->getKind()) {
#define UNCHECKED_TYPE(id, parent) \
  case TypeKind::id: \
    llvm_unreachable("generating an " #id "Type");
#define SUGARED_TYPE(id, parent) \
  case TypeKind::id: \
    return &getFragileTypeInfo(IGM, cast<id##Type>(TB)->getDesugaredType());
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
  case TypeKind::MetaType:
    return convertMetaTypeType(IGM, cast<MetaTypeType>(T));
  case TypeKind::Module:
    return convertModuleType(IGM, cast<ModuleType>(T));
  case TypeKind::BuiltinRawPointer:
    return createPrimitive(llvm::Type::getInt8PtrTy(Ctx), IGM.getPointerSize(),
                           IGM.getPointerAlignment());
  case TypeKind::BuiltinObjectPointer:
    return convertBuiltinObjectPointer(IGM);
  case TypeKind::BuiltinFloat:
    switch (cast<BuiltinFloatType>(T)->getFPKind()) {
    case BuiltinFloatType::IEEE16:
      return createPrimitive(llvm::Type::getHalfTy(Ctx),
                             Size(2), Alignment(2));
    case BuiltinFloatType::IEEE32:
      return createPrimitive(llvm::Type::getFloatTy(Ctx),
                             Size(4), Alignment(4));
    case BuiltinFloatType::IEEE64:
      return createPrimitive(llvm::Type::getDoubleTy(Ctx),
                             Size(8), Alignment(8));
    case BuiltinFloatType::IEEE80:
      return createPrimitive(llvm::Type::getX86_FP80Ty(Ctx),
                             Size(10), Alignment(16));
    case BuiltinFloatType::IEEE128:
      return createPrimitive(llvm::Type::getFP128Ty(Ctx),
                             Size(16), Alignment(16));
    case BuiltinFloatType::PPC128:
      return createPrimitive(llvm::Type::getPPC_FP128Ty(Ctx),
                             Size(16), Alignment(16));
    }
    llvm_unreachable("bad builtin floating-point type kind");
  case TypeKind::BuiltinInteger: {
    unsigned BitWidth = cast<BuiltinIntegerType>(T)->getBitWidth();
    unsigned ByteSize = (BitWidth+7U)/8U;
    // Round up the memory size and alignment to a power of 2.
    if (!llvm::isPowerOf2_32(ByteSize))
      ByteSize = llvm::NextPowerOf2(ByteSize);

    return createPrimitive(llvm::IntegerType::get(Ctx, BitWidth),
                           Size(ByteSize), Alignment(ByteSize));
  }
  case TypeKind::LValue:
    return convertLValueType(IGM, cast<LValueType>(TB));
  case TypeKind::Tuple:
    return convertTupleType(IGM, cast<TupleType>(TB));
  case TypeKind::OneOf:
    return convertOneOfType(IGM, cast<OneOfType>(TB));
  case TypeKind::Function:
    return convertFunctionType(IGM, cast<FunctionType>(TB));
  case TypeKind::Array:
    return convertArrayType(IGM, cast<ArrayType>(TB));
  case TypeKind::Protocol:
    llvm_unreachable("protocol not handled in IRGen yet");
  }
  llvm_unreachable("bad type kind");
}

/// emitTypeAlias - Emit a type alias.  You wouldn't think that these
/// would need IR support, but we apparently want to emit struct and
/// oneof declarations as these instead of as their own declarations.
void IRGenModule::emitTypeAlias(Type underlyingType) {
  if (OneOfType *oneof = dyn_cast<OneOfType>(underlyingType))
    return emitOneOfType(oneof);
}

/// createNominalType - Create a new nominal type.
llvm::StructType *IRGenModule::createNominalType(TypeAliasDecl *alias) {
  llvm::SmallString<32> typeName;
  llvm::raw_svector_ostream nameStream(typeName);
  LinkEntity::forNonFunction(alias).mangle(nameStream);

  return llvm::StructType::create(getLLVMContext(), nameStream.str());
}

/// Compute the explosion schema for the given type.
void IRGenModule::getSchema(Type type, ExplosionSchema &schema) {
  // As an optimization, avoid actually building a TypeInfo for any
  // obvious TupleTypes.  This assumes that a TupleType's explosion
  // schema is always the concatenation of its components schemata.
  if (TupleType *tuple = dyn_cast<TupleType>(type)) {
    for (const TupleTypeElt &field : tuple->getFields())
      getSchema(field.getType(), schema);
    return;
  }

  // Okay, that didn't work;  just do the general thing.
  getFragileTypeInfo(type).getSchema(schema);
}
<commit_msg>use cached type, thanks John<commit_after>//===--- GenTypes.cpp - Swift IR Generation For Types ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements IR generation for types in Swift.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/Decl.h"
#include "swift/AST/Types.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetData.h"

#include "GenType.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "Address.h"
#include "Explosion.h"
#include "Linking.h"

using namespace swift;
using namespace irgen;

bool TypeInfo::isSingleRetainablePointer(ResilienceScope scope) const {
  return false;
}

ExplosionSchema TypeInfo::getSchema(ExplosionKind kind) const {
  ExplosionSchema schema(kind);
  getSchema(schema);
  return schema;
}

/// Copy a value from one object to a new object, directly taking
/// responsibility for anything it might have.  This is like C++
/// move-initialization, except the old object will not be destroyed.
void TypeInfo::initializeWithTake(IRGenFunction &IGF,
                                  Address destAddr, Address srcAddr) const {
  // Prefer loads and stores if we won't make a million of them.
  // Maybe this should also require the scalars to have a fixed offset.
  ExplosionSchema schema = getSchema(ExplosionKind::Maximal);
  if (!schema.containsAggregate() && schema.size() <= 2) {
    Explosion copy(ExplosionKind::Maximal);
    load(IGF, srcAddr, copy);
    initialize(IGF, copy, destAddr);
    return;
  }

  // Otherwise, use a memcpy.
  IGF.emitMemCpy(destAddr.getAddress(), srcAddr.getAddress(),
                 StorageSize, std::min(destAddr.getAlignment(),
                                       srcAddr.getAlignment()));
}

static TypeInfo *invalidTypeInfo() { return (TypeInfo*) 1; }

namespace {
  /// Basic IR generation for primitive types, which are always
  /// represented as a single scalar.
  class PrimitiveTypeInfo : public TypeInfo {
  public:
    PrimitiveTypeInfo(llvm::Type *Type, Size S, Alignment A)
      : TypeInfo(Type, S, A) {}

    unsigned getExplosionSize(ExplosionKind kind) const {
      return 1;
    }

    void getSchema(ExplosionSchema &schema) const {
      schema.add(ExplosionSchema::Element::forScalar(getStorageType()));
    }

    void load(IRGenFunction &IGF, Address addr, Explosion &e) const {
      e.addUnmanaged(IGF.Builder.CreateLoad(addr));
    }

    void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
      IGF.Builder.CreateStore(e.claimUnmanagedNext(), addr);
    }

    void initialize(IRGenFunction &IGF, Explosion &e, Address addr) const {
      IGF.Builder.CreateStore(e.claimUnmanagedNext(), addr);
    }

    void reexplode(IRGenFunction &IGF, Explosion &src, Explosion &dest) const {
      src.transferInto(dest, 1);
    }

    void manage(IRGenFunction &IGF, Explosion &src, Explosion &dest) const {
      src.transferInto(dest, 1);
    }
  };
}

/// Constructs a type info which performs simple loads and stores of
/// the given IR type.
const TypeInfo *TypeConverter::createPrimitive(llvm::Type *type,
                                               Size size, Alignment align) {
  return new PrimitiveTypeInfo(type, size, align);
}

TypeConverter::TypeConverter() : FirstConverted(invalidTypeInfo()) {}

TypeConverter::~TypeConverter() {
  // Delete all the converted type infos.
  for (const TypeInfo *I = FirstConverted; I != invalidTypeInfo(); ) {
    const TypeInfo *Cur = I;
    I = Cur->NextConverted;
    delete Cur;
  }
}

/// Get the fragile type information for the given type.
const TypeInfo &IRGenFunction::getFragileTypeInfo(Type T) {
  return IGM.getFragileTypeInfo(T);
}

/// Get the fragile IR type for the given type.
llvm::Type *IRGenModule::getFragileType(Type T) {
  return getFragileTypeInfo(T).StorageType;
}

/// Get the fragile type information for the given type.
const TypeInfo &IRGenModule::getFragileTypeInfo(Type T) {
  return TypeConverter::getFragileTypeInfo(*this, T);
}

const TypeInfo &TypeConverter::getFragileTypeInfo(IRGenModule &IGM, Type T) {
  assert(!T.isNull());
  auto Entry = IGM.Types.Converted.find(T.getPointer());
  if (Entry != IGM.Types.Converted.end())
    return *Entry->second;

  const TypeInfo *Result = convertType(IGM, T);
  IGM.Types.Converted[T.getPointer()] = Result;

  // If the type info hasn't been added to the list of types, do so.
  if (!Result->NextConverted) {
    Result->NextConverted = IGM.Types.FirstConverted;
    IGM.Types.FirstConverted = Result;
  }

  return *Result;
}

const TypeInfo *TypeConverter::convertType(IRGenModule &IGM, Type T) {
  llvm::LLVMContext &Ctx = IGM.getLLVMContext();
  TypeBase *TB = T.getPointer();
  switch (TB->getKind()) {
#define UNCHECKED_TYPE(id, parent) \
  case TypeKind::id: \
    llvm_unreachable("generating an " #id "Type");
#define SUGARED_TYPE(id, parent) \
  case TypeKind::id: \
    return &getFragileTypeInfo(IGM, cast<id##Type>(TB)->getDesugaredType());
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
  case TypeKind::MetaType:
    return convertMetaTypeType(IGM, cast<MetaTypeType>(T));
  case TypeKind::Module:
    return convertModuleType(IGM, cast<ModuleType>(T));
  case TypeKind::BuiltinRawPointer:
    return createPrimitive(IGM.Int8PtrTy, IGM.getPointerSize(),
                           IGM.getPointerAlignment());
  case TypeKind::BuiltinObjectPointer:
    return convertBuiltinObjectPointer(IGM);
  case TypeKind::BuiltinFloat:
    switch (cast<BuiltinFloatType>(T)->getFPKind()) {
    case BuiltinFloatType::IEEE16:
      return createPrimitive(llvm::Type::getHalfTy(Ctx),
                             Size(2), Alignment(2));
    case BuiltinFloatType::IEEE32:
      return createPrimitive(llvm::Type::getFloatTy(Ctx),
                             Size(4), Alignment(4));
    case BuiltinFloatType::IEEE64:
      return createPrimitive(llvm::Type::getDoubleTy(Ctx),
                             Size(8), Alignment(8));
    case BuiltinFloatType::IEEE80:
      return createPrimitive(llvm::Type::getX86_FP80Ty(Ctx),
                             Size(10), Alignment(16));
    case BuiltinFloatType::IEEE128:
      return createPrimitive(llvm::Type::getFP128Ty(Ctx),
                             Size(16), Alignment(16));
    case BuiltinFloatType::PPC128:
      return createPrimitive(llvm::Type::getPPC_FP128Ty(Ctx),
                             Size(16), Alignment(16));
    }
    llvm_unreachable("bad builtin floating-point type kind");
  case TypeKind::BuiltinInteger: {
    unsigned BitWidth = cast<BuiltinIntegerType>(T)->getBitWidth();
    unsigned ByteSize = (BitWidth+7U)/8U;
    // Round up the memory size and alignment to a power of 2.
    if (!llvm::isPowerOf2_32(ByteSize))
      ByteSize = llvm::NextPowerOf2(ByteSize);

    return createPrimitive(llvm::IntegerType::get(Ctx, BitWidth),
                           Size(ByteSize), Alignment(ByteSize));
  }
  case TypeKind::LValue:
    return convertLValueType(IGM, cast<LValueType>(TB));
  case TypeKind::Tuple:
    return convertTupleType(IGM, cast<TupleType>(TB));
  case TypeKind::OneOf:
    return convertOneOfType(IGM, cast<OneOfType>(TB));
  case TypeKind::Function:
    return convertFunctionType(IGM, cast<FunctionType>(TB));
  case TypeKind::Array:
    return convertArrayType(IGM, cast<ArrayType>(TB));
  case TypeKind::Protocol:
    llvm_unreachable("protocol not handled in IRGen yet");
  }
  llvm_unreachable("bad type kind");
}

/// emitTypeAlias - Emit a type alias.  You wouldn't think that these
/// would need IR support, but we apparently want to emit struct and
/// oneof declarations as these instead of as their own declarations.
void IRGenModule::emitTypeAlias(Type underlyingType) {
  if (OneOfType *oneof = dyn_cast<OneOfType>(underlyingType))
    return emitOneOfType(oneof);
}

/// createNominalType - Create a new nominal type.
llvm::StructType *IRGenModule::createNominalType(TypeAliasDecl *alias) {
  llvm::SmallString<32> typeName;
  llvm::raw_svector_ostream nameStream(typeName);
  LinkEntity::forNonFunction(alias).mangle(nameStream);

  return llvm::StructType::create(getLLVMContext(), nameStream.str());
}

/// Compute the explosion schema for the given type.
void IRGenModule::getSchema(Type type, ExplosionSchema &schema) {
  // As an optimization, avoid actually building a TypeInfo for any
  // obvious TupleTypes.  This assumes that a TupleType's explosion
  // schema is always the concatenation of its components schemata.
  if (TupleType *tuple = dyn_cast<TupleType>(type)) {
    for (const TupleTypeElt &field : tuple->getFields())
      getSchema(field.getType(), schema);
    return;
  }

  // Okay, that didn't work;  just do the general thing.
  getFragileTypeInfo(type).getSchema(schema);
}
<|endoftext|>