<commit_before>// @(#)root/io:$Id$
// Author: Rene Brun   18/05/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFileCacheRead : a cache when reading files over the network         //
//                                                                      //
// A caching system to speed up network I/O, i.e. when there is         //
// no operating system caching support (like the buffer cache for       //
// local disk I/O). The cache makes sure that every I/O is done with    //
// a (large) fixed length buffer thereby avoiding many small I/O's.     //
// Currently the read cache system is used by the classes TNetFile,     //
// TXNetFile and TWebFile (via TFile::ReadBuffers()).                   //
//                                                                      //
// When processing TTree, TChain, a specialized class TTreeCache that   //
// derives from this class is automatically created.                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TEnv.h"
#include "TFile.h"
#include "TFileCacheRead.h"
#include "TFileCacheWrite.h"
#include "TMath.h"
#include "TXNetFile.h"

ClassImp(TFileCacheRead)

//______________________________________________________________________________
TFileCacheRead::TFileCacheRead() : TObject()
{
   // Default Constructor.

   fBufferSizeMin = 0;
   fBufferSize  = 0;
   fBufferLen   = 0;
   fNseek       = 0;
   fNtot        = 0;
   fNb          = 0;
   fSeekSize    = 0;
   fSeek        = 0;
   fSeekIndex   = 0;
   fSeekSort    = 0;
   fPos         = 0;
   fSeekLen     = 0;
   fSeekSortLen = 0;
   fSeekPos     = 0;
   fLen         = 0;
   fFile        = 0;
   fBuffer      = 0;
   fIsSorted    = kFALSE;
   fIsTransferred = kFALSE;

   fAsyncReading = kFALSE;
}

//_____________________________________________________________________________
TFileCacheRead::TFileCacheRead(TFile *file, Int_t buffersize)
           : TObject()
{
   // Creates a TFileCacheRead data structure.

   if (buffersize <=10000) fBufferSize = 100000;
   else fBufferSize = buffersize;

   fBufferSizeMin = fBufferSize;
   fBufferLen   = 0;
   fNseek       = 0;
   fNtot        = 0;
   fNb          = 0;
   fSeekSize    = 10000;
   fSeek        = new Long64_t[fSeekSize];
   fSeekIndex   = new Int_t[fSeekSize];
   fSeekSort    = new Long64_t[fSeekSize];
   fPos         = new Long64_t[fSeekSize];
   fSeekLen     = new Int_t[fSeekSize];
   fSeekSortLen = new Int_t[fSeekSize];
   fSeekPos     = new Int_t[fSeekSize];
   fLen         = new Int_t[fSeekSize];
   fFile        = file;

   fBuffer = 0;

   fAsyncReading = gEnv->GetValue("TFile.AsyncReading", 1);
   if (fAsyncReading) {
      // Check if asynchronous reading is supported by this TFile specialization
      fAsyncReading = kFALSE;
      if (file && !(file->ReadBufferAsync(0, 0)))
         fAsyncReading = kTRUE;
   }
   if (!fAsyncReading) {
      // we use sync primitives, hence we need the local buffer
      fBuffer = new char[fBufferSize];
   }

   fIsSorted    = kFALSE;
   fIsTransferred = kFALSE;
   if (file) file->SetCacheRead(this);
}

//_____________________________________________________________________________
TFileCacheRead::~TFileCacheRead()
{
   // Destructor.

   delete [] fSeek;
   delete [] fSeekIndex;
   delete [] fSeekSort;
   delete [] fPos;
   delete [] fSeekLen;
   delete [] fSeekSortLen;
   delete [] fSeekPos;
   delete [] fLen;
   delete [] fBuffer;
}

//_____________________________________________________________________________
void TFileCacheRead::Prefetch(Long64_t pos, Int_t len)
{
   // Add block of length len at position pos in the list of blocks to
   // be prefetched. If pos <= 0 the current blocks (if any) are reset.

   fIsSorted = kFALSE;
   fIsTransferred = kFALSE;
   if (pos <= 0) {
      fNseek = 0;
      fNtot  = 0;
      return;
   }
   if (fNseek >= fSeekSize) {
      //reallocate buffers
      fSeekSize *= 2;
      Long64_t *aSeek        = new Long64_t[fSeekSize];
      Int_t    *aSeekIndex   = new Int_t[fSeekSize];
      Long64_t *aSeekSort    = new Long64_t[fSeekSize];
      Long64_t *aPos         = new Long64_t[fSeekSize];
      Int_t    *aSeekLen     = new Int_t[fSeekSize];
      Int_t    *aSeekSortLen = new Int_t[fSeekSize];
      Int_t    *aSeekPos     = new Int_t[fSeekSize];
      Int_t    *aLen         = new Int_t[fSeekSize];
      for (Int_t i=0;i<fNseek;i++) {
         aSeek[i]        = fSeek[i];
         aSeekIndex[i]   = fSeekIndex[i];
         aSeekSort[i]    = fSeekSort[i];
         aPos[i]         = fPos[i];
         aSeekLen[i]     = fSeekLen[i];
         aSeekSortLen[i] = fSeekSortLen[i];
         aSeekPos[i]     = fSeekPos[i];
         aLen[i]         = fLen[i];
      }
      delete [] fSeek;
      delete [] fSeekIndex;
      delete [] fSeekSort;
      delete [] fPos;
      delete [] fSeekLen;
      delete [] fSeekSortLen;
      delete [] fSeekPos;
      delete [] fLen;
      fSeek        = aSeek;
      fSeekIndex   = aSeekIndex;
      fSeekSort    = aSeekSort;
      fPos         = aPos;
      fSeekLen     = aSeekLen;
      fSeekSortLen = aSeekSortLen;
      fSeekPos     = aSeekPos;
      fLen         = aLen;
   }

   fSeek[fNseek] = pos;
   fSeekLen[fNseek] = len;
   fNseek++;
   fNtot += len;
}

//_____________________________________________________________________________
void TFileCacheRead::Print(Option_t *option) const
{
   // Print class internal structure.

   TString opt = option;
   opt.ToLower();
   printf("Number of blocks: %d, total size : %d\n",fNseek,fNtot);
   if (!opt.Contains("a")) return;
   for (Int_t i=0;i<fNseek;i++) {
      if (fIsSorted && !opt.Contains("s")) {
         printf("block: %5d, from: %lld to %lld, len=%d bytes\n",i,fSeekSort[i],fSeekSort[i]+fSeekSortLen[i],fSeekSortLen[i]);
      } else {
         printf("block: %5d, from: %lld to %lld, len=%d bytes\n",i,fSeek[i],fSeek[i]+fSeekLen[i],fSeekLen[i]);
      }
   }
   printf ("Number of long buffers = %d\n",fNb);
   for (Int_t j=0;j<fNb;j++) {
      printf("fPos[%d]=%lld, fLen=%d\n",j,fPos[j],fLen[j]);
   }
}

//_____________________________________________________________________________
Int_t TFileCacheRead::ReadBuffer(char *buf, Long64_t pos, Int_t len) {
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // otherwise need to make a normal read from file. Returns -1 in case of
   // read error, 0 in case not in cache, 1 in case read from cache.
   Int_t loc = 0;
   return ReadBufferExt(buf, pos, len, loc);

}

//_____________________________________________________________________________
Int_t TFileCacheRead::ReadBufferExt(char *buf, Long64_t pos, Int_t len, Int_t &loc)
{
   // Base function for ReadBuffer. Also gives out the position
   // of the block in the internal buffer. This helps TTreeCacheUnzip to avoid
   // doing twice the binary search

   if (fNseek > 0 && !fIsSorted) {
      Sort();

      // If ReadBufferAsync is not supported by this implementation...
      if (!fAsyncReading) {
         // Then we use the vectored read to read everything now
         if (fFile->ReadBuffers(fBuffer,fPos,fLen,fNb)) {
            return -1;
         }
         fIsTransferred = kTRUE;
      } else {
         // In any case, we'll start to request the chunks.
         // This implementation simply reads all the chunks in advance
         // in the async way.

         // Use the async readv instead of single reads
         fFile->ReadBuffers(0, 0, 0, 0); //Clear the XrdClient cache
         if (fFile->ReadBuffers(0,fPos,fLen,fNb)) {
            return -1;
         }
         fIsTransferred = kTRUE;

      }
   }

   // in case we are writing and reading to/from this file, we much check
   // if this buffer is in the write cache (not yet written to the file)
   if (TFileCacheWrite *cachew = fFile->GetCacheWrite()) {
      if (cachew->ReadBuffer(buf,pos,len) == 0) {
         fFile->Seek(pos+len);
         return 1;
      }
   }

   // If asynchronous reading is supported by this implementation...
   if (fAsyncReading) {

      Int_t retval;
      loc = (Int_t)TMath::BinarySearch(fNseek,fSeekSort,pos);

      // Now we dont have to look for it in the local buffer
      // if it's async, we expect that the communication library
      // will handle it more efficiently than we can do here

      // We use the internal list just to notify if the list is to be reconstructed
      if (loc >= 0 && loc < fNseek && pos == fSeekSort[loc]) {
         // Block found, the caller will get it

         if (buf) {
            fFile->Seek(pos);

            if (fFile->ReadBuffer(buf, len)) {
               return -1;
            }
            fFile->Seek(pos+len);
         }

         retval = 1;
      } else {
         // Block not found in the list, we report it as a miss
         retval = 0;
      }

      if (gDebug > 0)
         Info("ReadBuffer","pos=%lld, len=%d, retval=%d", pos, len, retval);

      return retval;
   } else {

      loc = (Int_t)TMath::BinarySearch(fNseek,fSeekSort,pos);
      if (loc >= 0 && loc <fNseek && pos == fSeekSort[loc]) {
         if (buf) {
            memcpy(buf,&fBuffer[fSeekPos[loc]],len);
            fFile->Seek(pos+len);
         }
         return 1;
      }
   }

   return 0;
}

//_____________________________________________________________________________
void TFileCacheRead::SetFile(TFile *file)
{
   // Set the file using this cache and reset the current blocks (if any).

   fFile = file;

   if (fAsyncReading) {
      // If asynchronous reading is not supported by this TFile specialization
      // we use sync primitives, hence we need the local buffer
      if (file && file->ReadBufferAsync(0, 0)) {
         fAsyncReading = kFALSE;
         fBuffer    = new char[fBufferSize];

      }
   }

   Prefetch(0,0);
}

//_____________________________________________________________________________
void TFileCacheRead::Sort()
{
   // Sort buffers to be prefetched in increasing order of positions.
   // Merge consecutive blocks if necessary.

   if (!fNseek) return;
   TMath::Sort(fNseek,fSeek,fSeekIndex,kFALSE);
   Int_t i;
   Int_t nb = 0;
   for (i=0;i<fNseek;i++) {
      Int_t ind = fSeekIndex[i];
      fSeekSort[i] = fSeek[ind];
      fSeekSortLen[i] = fSeekLen[ind];
   }
   if (fNtot > fBufferSizeMin) {
      fBufferSize = fNtot + 100;
      delete [] fBuffer;
      fBuffer = 0;
      // If ReadBufferAsync is not supported by this implementation
      // it means that we are using sync primitives, hence we need the local buffer
      if (!fAsyncReading)
         fBuffer = new char[fBufferSize];
   }
   fPos[0]  = fSeekSort[0];
   fLen[0]  = fSeekSortLen[0];
   fSeekPos[0] = 0;
   for (i=1;i<fNseek;i++) {
      fSeekPos[i] = fSeekPos[i-1] + fSeekSortLen[i-1];
      if ((fSeekSort[i] != fSeekSort[i-1]+fSeekSortLen[i-1]) ||
          (fLen[nb] > 2000000)) {
         nb++;
         fPos[nb] = fSeekSort[i];
         fLen[nb] = fSeekSortLen[i];
      } else {
         fLen[nb] += fSeekSortLen[i];
      }
   }
   fNb = nb+1;
   fIsSorted = kTRUE;
}
<commit_msg>correct coding style.<commit_after>// @(#)root/io:$Id$
// Author: Rene Brun   18/05/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFileCacheRead : a cache when reading files over the network         //
//                                                                      //
// A caching system to speed up network I/O, i.e. when there is         //
// no operating system caching support (like the buffer cache for       //
// local disk I/O). The cache makes sure that every I/O is done with    //
// a (large) fixed length buffer thereby avoiding many small I/O's.     //
// Currently the read cache system is used by the classes TNetFile,     //
// TXNetFile and TWebFile (via TFile::ReadBuffers()).                   //
//                                                                      //
// When processing TTree, TChain, a specialized class TTreeCache that   //
// derives from this class is automatically created.                    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TEnv.h"
#include "TFile.h"
#include "TFileCacheRead.h"
#include "TFileCacheWrite.h"
#include "TMath.h"
#include "TXNetFile.h"

ClassImp(TFileCacheRead)

//______________________________________________________________________________
TFileCacheRead::TFileCacheRead() : TObject()
{
   // Default Constructor.

   fBufferSizeMin = 0;
   fBufferSize  = 0;
   fBufferLen   = 0;
   fNseek       = 0;
   fNtot        = 0;
   fNb          = 0;
   fSeekSize    = 0;
   fSeek        = 0;
   fSeekIndex   = 0;
   fSeekSort    = 0;
   fPos         = 0;
   fSeekLen     = 0;
   fSeekSortLen = 0;
   fSeekPos     = 0;
   fLen         = 0;
   fFile        = 0;
   fBuffer      = 0;
   fIsSorted    = kFALSE;
   fIsTransferred = kFALSE;

   fAsyncReading = kFALSE;
}

//_____________________________________________________________________________
TFileCacheRead::TFileCacheRead(TFile *file, Int_t buffersize)
           : TObject()
{
   // Creates a TFileCacheRead data structure.

   if (buffersize <=10000) fBufferSize = 100000;
   else fBufferSize = buffersize;

   fBufferSizeMin = fBufferSize;
   fBufferLen   = 0;
   fNseek       = 0;
   fNtot        = 0;
   fNb          = 0;
   fSeekSize    = 10000;
   fSeek        = new Long64_t[fSeekSize];
   fSeekIndex   = new Int_t[fSeekSize];
   fSeekSort    = new Long64_t[fSeekSize];
   fPos         = new Long64_t[fSeekSize];
   fSeekLen     = new Int_t[fSeekSize];
   fSeekSortLen = new Int_t[fSeekSize];
   fSeekPos     = new Int_t[fSeekSize];
   fLen         = new Int_t[fSeekSize];
   fFile        = file;

   fBuffer = 0;

   fAsyncReading = gEnv->GetValue("TFile.AsyncReading", 1);
   if (fAsyncReading) {
      // Check if asynchronous reading is supported by this TFile specialization
      fAsyncReading = kFALSE;
      if (file && !(file->ReadBufferAsync(0, 0)))
         fAsyncReading = kTRUE;
   }
   if (!fAsyncReading) {
      // we use sync primitives, hence we need the local buffer
      fBuffer = new char[fBufferSize];
   }

   fIsSorted    = kFALSE;
   fIsTransferred = kFALSE;
   if (file) file->SetCacheRead(this);
}

//_____________________________________________________________________________
TFileCacheRead::~TFileCacheRead()
{
   // Destructor.

   delete [] fSeek;
   delete [] fSeekIndex;
   delete [] fSeekSort;
   delete [] fPos;
   delete [] fSeekLen;
   delete [] fSeekSortLen;
   delete [] fSeekPos;
   delete [] fLen;
   delete [] fBuffer;
}

//_____________________________________________________________________________
void TFileCacheRead::Prefetch(Long64_t pos, Int_t len)
{
   // Add block of length len at position pos in the list of blocks to
   // be prefetched. If pos <= 0 the current blocks (if any) are reset.

   fIsSorted = kFALSE;
   fIsTransferred = kFALSE;
   if (pos <= 0) {
      fNseek = 0;
      fNtot  = 0;
      return;
   }
   if (fNseek >= fSeekSize) {
      //reallocate buffers
      fSeekSize *= 2;
      Long64_t *aSeek        = new Long64_t[fSeekSize];
      Int_t    *aSeekIndex   = new Int_t[fSeekSize];
      Long64_t *aSeekSort    = new Long64_t[fSeekSize];
      Long64_t *aPos         = new Long64_t[fSeekSize];
      Int_t    *aSeekLen     = new Int_t[fSeekSize];
      Int_t    *aSeekSortLen = new Int_t[fSeekSize];
      Int_t    *aSeekPos     = new Int_t[fSeekSize];
      Int_t    *aLen         = new Int_t[fSeekSize];
      for (Int_t i=0;i<fNseek;i++) {
         aSeek[i]        = fSeek[i];
         aSeekIndex[i]   = fSeekIndex[i];
         aSeekSort[i]    = fSeekSort[i];
         aPos[i]         = fPos[i];
         aSeekLen[i]     = fSeekLen[i];
         aSeekSortLen[i] = fSeekSortLen[i];
         aSeekPos[i]     = fSeekPos[i];
         aLen[i]         = fLen[i];
      }
      delete [] fSeek;
      delete [] fSeekIndex;
      delete [] fSeekSort;
      delete [] fPos;
      delete [] fSeekLen;
      delete [] fSeekSortLen;
      delete [] fSeekPos;
      delete [] fLen;
      fSeek        = aSeek;
      fSeekIndex   = aSeekIndex;
      fSeekSort    = aSeekSort;
      fPos         = aPos;
      fSeekLen     = aSeekLen;
      fSeekSortLen = aSeekSortLen;
      fSeekPos     = aSeekPos;
      fLen         = aLen;
   }

   fSeek[fNseek] = pos;
   fSeekLen[fNseek] = len;
   fNseek++;
   fNtot += len;
}

//_____________________________________________________________________________
void TFileCacheRead::Print(Option_t *option) const
{
   // Print class internal structure.

   TString opt = option;
   opt.ToLower();
   printf("Number of blocks: %d, total size : %d\n",fNseek,fNtot);
   if (!opt.Contains("a")) return;
   for (Int_t i=0;i<fNseek;i++) {
      if (fIsSorted && !opt.Contains("s")) {
         printf("block: %5d, from: %lld to %lld, len=%d bytes\n",i,fSeekSort[i],fSeekSort[i]+fSeekSortLen[i],fSeekSortLen[i]);
      } else {
         printf("block: %5d, from: %lld to %lld, len=%d bytes\n",i,fSeek[i],fSeek[i]+fSeekLen[i],fSeekLen[i]);
      }
   }
   printf ("Number of long buffers = %d\n",fNb);
   for (Int_t j=0;j<fNb;j++) {
      printf("fPos[%d]=%lld, fLen=%d\n",j,fPos[j],fLen[j]);
   }
}

//_____________________________________________________________________________
Int_t TFileCacheRead::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // otherwise need to make a normal read from file. Returns -1 in case of
   // read error, 0 in case not in cache, 1 in case read from cache.

   Int_t loc = 0;
   return ReadBufferExt(buf, pos, len, loc);
}

//_____________________________________________________________________________
Int_t TFileCacheRead::ReadBufferExt(char *buf, Long64_t pos, Int_t len, Int_t &loc)
{
   // Base function for ReadBuffer. Also gives out the position
   // of the block in the internal buffer. This helps TTreeCacheUnzip to avoid
   // doing twice the binary search

   if (fNseek > 0 && !fIsSorted) {
      Sort();

      // If ReadBufferAsync is not supported by this implementation...
      if (!fAsyncReading) {
         // Then we use the vectored read to read everything now
         if (fFile->ReadBuffers(fBuffer,fPos,fLen,fNb)) {
            return -1;
         }
         fIsTransferred = kTRUE;
      } else {
         // In any case, we'll start to request the chunks.
         // This implementation simply reads all the chunks in advance
         // in the async way.

         // Use the async readv instead of single reads
         fFile->ReadBuffers(0, 0, 0, 0); //Clear the XrdClient cache
         if (fFile->ReadBuffers(0,fPos,fLen,fNb)) {
            return -1;
         }
         fIsTransferred = kTRUE;

      }
   }

   // in case we are writing and reading to/from this file, we much check
   // if this buffer is in the write cache (not yet written to the file)
   if (TFileCacheWrite *cachew = fFile->GetCacheWrite()) {
      if (cachew->ReadBuffer(buf,pos,len) == 0) {
         fFile->Seek(pos+len);
         return 1;
      }
   }

   // If asynchronous reading is supported by this implementation...
   if (fAsyncReading) {

      Int_t retval;
      loc = (Int_t)TMath::BinarySearch(fNseek,fSeekSort,pos);

      // Now we dont have to look for it in the local buffer
      // if it's async, we expect that the communication library
      // will handle it more efficiently than we can do here

      // We use the internal list just to notify if the list is to be reconstructed
      if (loc >= 0 && loc < fNseek && pos == fSeekSort[loc]) {
         // Block found, the caller will get it

         if (buf) {
            fFile->Seek(pos);

            if (fFile->ReadBuffer(buf, len)) {
               return -1;
            }
            fFile->Seek(pos+len);
         }

         retval = 1;
      } else {
         // Block not found in the list, we report it as a miss
         retval = 0;
      }

      if (gDebug > 0)
         Info("ReadBuffer","pos=%lld, len=%d, retval=%d", pos, len, retval);

      return retval;
   } else {

      loc = (Int_t)TMath::BinarySearch(fNseek,fSeekSort,pos);
      if (loc >= 0 && loc <fNseek && pos == fSeekSort[loc]) {
         if (buf) {
            memcpy(buf,&fBuffer[fSeekPos[loc]],len);
            fFile->Seek(pos+len);
         }
         return 1;
      }
   }

   return 0;
}

//_____________________________________________________________________________
void TFileCacheRead::SetFile(TFile *file)
{
   // Set the file using this cache and reset the current blocks (if any).

   fFile = file;

   if (fAsyncReading) {
      // If asynchronous reading is not supported by this TFile specialization
      // we use sync primitives, hence we need the local buffer
      if (file && file->ReadBufferAsync(0, 0)) {
         fAsyncReading = kFALSE;
         fBuffer    = new char[fBufferSize];

      }
   }

   Prefetch(0,0);
}

//_____________________________________________________________________________
void TFileCacheRead::Sort()
{
   // Sort buffers to be prefetched in increasing order of positions.
   // Merge consecutive blocks if necessary.

   if (!fNseek) return;
   TMath::Sort(fNseek,fSeek,fSeekIndex,kFALSE);
   Int_t i;
   Int_t nb = 0;
   for (i=0;i<fNseek;i++) {
      Int_t ind = fSeekIndex[i];
      fSeekSort[i] = fSeek[ind];
      fSeekSortLen[i] = fSeekLen[ind];
   }
   if (fNtot > fBufferSizeMin) {
      fBufferSize = fNtot + 100;
      delete [] fBuffer;
      fBuffer = 0;
      // If ReadBufferAsync is not supported by this implementation
      // it means that we are using sync primitives, hence we need the local buffer
      if (!fAsyncReading)
         fBuffer = new char[fBufferSize];
   }
   fPos[0]  = fSeekSort[0];
   fLen[0]  = fSeekSortLen[0];
   fSeekPos[0] = 0;
   for (i=1;i<fNseek;i++) {
      fSeekPos[i] = fSeekPos[i-1] + fSeekSortLen[i-1];
      if ((fSeekSort[i] != fSeekSort[i-1]+fSeekSortLen[i-1]) ||
          (fLen[nb] > 2000000)) {
         nb++;
         fPos[nb] = fSeekSort[i];
         fLen[nb] = fSeekSortLen[i];
      } else {
         fLen[nb] += fSeekSortLen[i];
      }
   }
   fNb = nb+1;
   fIsSorted = kTRUE;
}
<|endoftext|>


<commit_before>#include "Hotkeys.h"
#include "Actions.h"

std::map<const std::string, unsigned int> hotkeysMap = std::map<const std::string, unsigned int>();
std::map<const unsigned int, Hotkey*> hotkey = std::map<const unsigned int, Hotkey*>();

void InitHotkeysMap()
{
	hotkeysMap["space"] = VK_SPACE;
	hotkeysMap[","] = VK_OEM_COMMA;
	hotkeysMap["."] = VK_OEM_PERIOD;
}

Hotkey::Hotkey(const std::string action_name, const std::string key_name, const std::string alt_str,
			   const std::string control_str, const std::string shift_str, const std::string win_str)
{
	key = GetKeyCode(key_name);

	alt = IsKeyUsed(alt_str);
	control = IsKeyUsed(control_str);
	shift = IsKeyUsed(shift_str);
	win = IsKeyUsed(win_str);

	/*id = key + (alt ? 1000 * MOD_ALT : 0) + (control ? 10000 * MOD_CONTROL : 0) +
		(shift ? 100000 * MOD_SHIFT : 0) + (win ? 1000000 * MOD_WIN : 0);*/

	Action = GetAction(action_name);
}

Hotkey::~Hotkey()
{
	/* nothing to do */
}

void (*Hotkey::GetAction(const std::string action_name))(void)
{
	switch (actionsMap[action_name])
	{
	case eActionPlayPause:
		return &PlayPause;
	case eActionPreviousTrack:
		return &PreviousTrack;
	case eActionNextTrack:
		return &NextTrack;
	default:
		return 0;
	}
}

unsigned int Hotkey::GetKeyCode(const std::string key_name)
{
	return hotkeysMap[key_name];
}

bool Hotkey::IsKeyUsed(const std::string key_str)
{
	return (key_str == std::string("true"));
}

void Hotkey::PerformAction()
{
	if(Action > 0)
		Action();
}<commit_msg>Added more hotkeys<commit_after>#include "Hotkeys.h"
#include "Actions.h"

std::map<const std::string, unsigned int> hotkeysMap = std::map<const std::string, unsigned int>();
std::map<const unsigned int, Hotkey*> hotkey = std::map<const unsigned int, Hotkey*>();

void InitHotkeysMap()
{
	char str[4];
	for (int i = 0; i < 4; i++)
		str[i] = '\0';

	// add 0-9
	for (unsigned int i = 0x30; i < 0x3A; i++) {
		str[0] = i;
		hotkeysMap[std::string(str)] = i;
	}

	// add A-Z
	for (unsigned int i = 0x41; i < 0x5A; i++) {
		str[0] = i;
		hotkeysMap[std::string(str)] = i;
	}

	// add a-z
	unsigned int j  = 0x61;
	for (unsigned int i = 0x41; i < 0x5A; i++) {
		str[0] = j++;
		hotkeysMap[std::string(str)] = i;
	}

	str[0] = 'F';
	j  = 0x31;
	// add F1-F9
	for (unsigned int i = 0x70; i < 0x79; i++) {
		str[1] = j++;
		hotkeysMap[std::string(str)] = i;
	}

	str[1] = '1';
	j  = 0x30;
	// add F10-F19
	for (unsigned int i = 0x79; i < 0x83; i++) {
		str[2] = j++;
		hotkeysMap[std::string(str)] = i;
	}

	str[1] = '2';
	j  = 0x30;
	// add F20-F24
	for (unsigned int i = 0x83; i < 0x88; i++) {
		str[2] = j++;
		hotkeysMap[std::string(str)] = i;
	}

	hotkeysMap["Spacebar"] = VK_SPACE;
	hotkeysMap["Backspace"] = VK_BACK;
	hotkeysMap["Tab"] = VK_TAB;
	hotkeysMap["Escape"] = VK_ESCAPE;

	hotkeysMap["PageUp"] = VK_PRIOR;
	hotkeysMap["PageDown"] = VK_NEXT;

	hotkeysMap["End"] = VK_END;
	hotkeysMap["Home"] = VK_HOME;

	hotkeysMap["Left"] = VK_LEFT;
	hotkeysMap["Up"] = VK_UP;
	hotkeysMap["Right"] = VK_RIGHT;
	hotkeysMap["Down"] = VK_DOWN;

	hotkeysMap["Insert"] = VK_INSERT;
	hotkeysMap["Delete"] = VK_DELETE;

	hotkeysMap["PrintScreen"] = VK_SNAPSHOT;
	hotkeysMap["Pause"] = VK_PAUSE;
	hotkeysMap["NumLock"] = VK_NUMLOCK;

	hotkeysMap["-"] = VK_SUBTRACT;
	hotkeysMap["="] = VK_ADD;
	hotkeysMap["/"] = VK_DIVIDE;
	hotkeysMap[","] = VK_OEM_COMMA;
	hotkeysMap["."] = VK_OEM_PERIOD;
}

Hotkey::Hotkey(const std::string action_name, const std::string key_name, const std::string alt_str,
			   const std::string control_str, const std::string shift_str, const std::string win_str)
{
	key = GetKeyCode(key_name);

	alt = IsKeyUsed(alt_str);
	control = IsKeyUsed(control_str);
	shift = IsKeyUsed(shift_str);
	win = IsKeyUsed(win_str);

	/*id = key + (alt ? 1000 * MOD_ALT : 0) + (control ? 10000 * MOD_CONTROL : 0) +
		(shift ? 100000 * MOD_SHIFT : 0) + (win ? 1000000 * MOD_WIN : 0);*/

	Action = GetAction(action_name);
}

Hotkey::~Hotkey()
{
	/* nothing to do */
}

void (*Hotkey::GetAction(const std::string action_name))(void)
{
	switch (actionsMap[action_name])
	{
	case eActionPlayPause:
		return &PlayPause;
	case eActionPreviousTrack:
		return &PreviousTrack;
	case eActionNextTrack:
		return &NextTrack;
	default:
		return 0;
	}
}

unsigned int Hotkey::GetKeyCode(const std::string key_name)
{
	return hotkeysMap[key_name];
}

bool Hotkey::IsKeyUsed(const std::string key_str)
{
	return (key_str == std::string("true"));
}

void Hotkey::PerformAction()
{
	if(Action > 0)
		Action();
}<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2018 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  @file JPetTaskIO.cpp
 */

#include "./JPetOptionsGenerator/JPetOptionsGeneratorTools.h"
#include "./JPetCommonTools/JPetCommonTools.h"
#include "./JPetTreeHeader/JPetTreeHeader.h"
#include "./JPetUserTask/JPetUserTask.h"
#include "./JPetTask/JPetTask.h"
#include "./JPetData/JPetData.h"
#include "./JPetLoggerInclude.h"
#include "JPetTaskIOTools.h"
#include "JPetTaskIO.h"
#include "./version.h"
#include <cassert>
#include <memory>

JPetTaskIO::JPetTaskIO(const char* name, const char* in_file_type, const char* out_file_type):
  JPetTask(name), fTaskInfo(in_file_type, out_file_type, "", false)
{
  if (std::string(out_file_type).empty()) {
    fIsOutput = false;
  }
  if (std::string(in_file_type).empty()) {
    fIsInput = false;
  }
}

JPetTaskIO::~JPetTaskIO() {}

bool JPetTaskIO::init(const JPetParams& params)
{
  using namespace jpet_options_tools;
  setParams(params);
  auto opts = fParams.getOptions();

  bool isOK = false;
  std::string inputFilename;
  std::string outFileFullPath;
  bool resetOutputPath = false;
  std::tie(isOK, inputFilename, outFileFullPath, resetOutputPath) = setInputAndOutputFile(opts);
  fTaskInfo.fOutFileFullPath = outFileFullPath;
  fTaskInfo.fResetOutputPath = resetOutputPath;

  auto subTaskName = getFirstSubTaskName();
  if (!isOK) {
    ERROR("Some error occured in setInputAndOutputFile, subtask name:" + subTaskName);
    return false;
  }

  if (isInput()) {
    if (!createInputObjects(inputFilename.c_str())) {
      ERROR("createInputObjects with the input file:" + inputFilename);
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
  }
  if (isOutput()) {
    if (!createOutputObjects(outFileFullPath.c_str())) {
      ERROR("createOutputObjects with the output file:" + outFileFullPath);
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
  }
  return true;
}

bool JPetTaskIO::run(const JPetDataInterface&)
{
  using namespace jpet_options_tools;
  if (fSubTasks.empty()) {
    ERROR("No subTask set");
    return false;
  }
  if (isInput()) {
    if (!fInputHandler) {
      ERROR("No inputHandler set");
      return false;
    }
  }
  for (const auto& pTask : fSubTasks) {
    auto subTaskName = pTask->getName();
    auto ok = pTask->init(fParams);
    if (!ok) {
      WARNING("In init() of:" + subTaskName + ". run()  and terminate() of this task will be skipped.");
      continue;
    }

    if (isInput()) {
      assert(fInputHandler);
      bool isOK = fInputHandler->setEntryRange(fParams.getOptions());
      if (!isOK) {
        ERROR("Some error occured in setEntryRange");
        return false;
      }
      auto lastEvent = fInputHandler->getLastEntryNumber();
      assert(lastEvent >= 0);
      do {
        if (isProgressBar(fParams.getOptions())) {
          displayProgressBar(subTaskName, fInputHandler->getCurrentEntryNumber(), lastEvent);
        }
        JPetData event(fInputHandler->getEntry());
        ok = pTask->run(event);
        if (!ok) {
          ERROR("In run() of:" + subTaskName + ". ");
        }
        if (isOutput()) {
          if (!fOutputHandler->writeEventToFile(pTask.get())) {
            ERROR("Some problems occured, while writing the event to file.");
            return false;
          }
        }
      } while (fInputHandler->nextEntry());

    } else {
      JPetDataInterface dummyEvent;
      pTask->run(dummyEvent);
    }

    JPetParams subTaskParams;
    ok = pTask->terminate(subTaskParams);
    if (!ok) {
      ERROR("In terminate() of:" + subTaskName + ". ");
      return false;
    }
    fParams = mergeWithExtraParams(fParams, subTaskParams);
  }
  return true;
}

bool JPetTaskIO::terminate(JPetParams& output_params)
{
  auto subTaskName = getFirstSubTaskName();
  if (isOutput()) {
    auto newOpts = JPetTaskIOTools::setOutputOptions(fParams, fTaskInfo.fResetOutputPath, fTaskInfo.fOutFileFullPath);
    output_params = JPetParams(newOpts, fParams.getParamManagerAsShared());
  } else {
    output_params = fParams;
  }

  if (isOutput()) {
    if (!fHeader) {
      ERROR("Tree header is not set,");
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
    if (!fStatistics.get()) {
      ERROR("Statistics container with histograms is not set.");
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
    fOutputHandler->saveAndCloseOutput(getParamManager(), fHeader, fStatistics.get(), fSubTasksStatistics);
  }
  if (isInput()) {
    if (!fInputHandler) {
      ERROR("fInputHandler set to null.");
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
    fInputHandler->closeInput();
  }
  return true;
}

void JPetTaskIO::addSubTask(std::unique_ptr<JPetTaskInterface> subTask)
{
  if (dynamic_cast<JPetUserTask*>(subTask.get()) == nullptr) {
    ERROR("JPetTaskIO currently only allows JPetUserTask as subtask");
  }
  fSubTasks.push_back(std::move(subTask));
}

void JPetTaskIO::displayProgressBar(std::string taskName, int currentEventNumber, int numberOfEvents) const
{
  return fProgressBar.display(taskName, currentEventNumber, numberOfEvents);
}

/**
 * @brief Currently this method passes "stopIteration_bool" option from subTask to fParams if present.
 */
JPetParams JPetTaskIO::mergeWithExtraParams(const JPetParams& oldParams, const JPetParams& extraParams) const
{
  using namespace jpet_options_tools;
  using namespace jpet_options_generator_tools;
  auto oldOpts = oldParams.getOptions();
  auto extraOpts = extraParams.getOptions();
  // @todo this is hardcoded and should be moved somewhere.
  const std::string stopIterationOptName = "stopIteration_bool";
  if (isOptionSet(extraOpts, stopIterationOptName)) {
    oldOpts[stopIterationOptName] = getOptionValue(extraOpts, stopIterationOptName);
  }
  return JPetParams(oldOpts, oldParams.getParamManagerAsShared());
}

void JPetTaskIO::setParams(const JPetParams& opts)
{
  fParams = opts;
}

JPetParams JPetTaskIO::getParams() const
{
  return fParams;
}

bool JPetTaskIO::isOutput() const
{
  return fIsOutput;
}

bool JPetTaskIO::isInput() const
{
  return fIsInput;
}

/**
 * @return (isOK, inputFile, outputFileFullPath, isResetOutputPath) based on provided options.
 * If isOK is set to false, that means that an error has occured.
 */
std::tuple<bool, std::string, std::string, bool> JPetTaskIO::setInputAndOutputFile(const OptsStrAny opts) const
{
  // We cannot remove this method completely and leave the one from JPetTaskIOTools, because it is overloaded in JPetScopeLoader class.
  return JPetTaskIOTools::setInputAndOutputFile(opts, fTaskInfo.fResetOutputPath, fTaskInfo.fInFileType, fTaskInfo.fOutFileType);
}

bool JPetTaskIO::createInputObjects(const char* inputFilename)
{
  fInputHandler = jpet_common_tools::make_unique<JPetInputHandler>();
  return fInputHandler->openInput(inputFilename, fParams);
}

bool JPetTaskIO::createOutputObjects(const char* outputFilename)
{
  if (!isOutput()) {
    ERROR("isOutput set to false and you are trying to createOutputObjects");
    return false;
  }
  fOutputHandler = jpet_common_tools::make_unique<JPetOutputHandler>(outputFilename);
  if (!fOutputHandler) {
    ERROR("OutputHandler is not set, cannot creat output file.");
    return false;
  }
  using namespace jpet_options_tools;
  auto options = fParams.getOptions();

  if (FileTypeChecker::getInputFileType(options) == FileTypeChecker::kHldRoot ||
      FileTypeChecker::getInputFileType(options) == FileTypeChecker::kMCGeant ) {

    fHeader = new JPetTreeHeader(getRunNumber(options));
    fHeader->setFrameworkVersion(FRAMEWORK_VERSION);
    fHeader->setFrameworkRevision(FRAMEWORK_REVISION);

    // add general info to the Tree header
    fHeader->setBaseFileName(getInputFile(options).c_str());
  } else {
    if (isInput()) {
      // read the header from the previous analysis stage
      fHeader = fInputHandler->getHeaderClone();
    } else {
      ERROR("We are trying to load Tree Header from the input file, and no input is set.");
      return false;
    }
  }

  fStatistics = jpet_common_tools::make_unique<JPetStatistics>();

  // add info about this module to the processing stages' history in Tree header
  for (auto fSubTask = fSubTasks.begin(); fSubTask != fSubTasks.end(); fSubTask++) {
    auto task = dynamic_cast<JPetUserTask*>((*fSubTask).get());
    fHeader->addStageInfo(task->getName(), "", 0,
                          JPetCommonTools::getTimeString());
  }

  if (!fSubTasks.empty()) {
    int i = 0;
    for (auto fSubTask = fSubTasks.begin(); fSubTask != fSubTasks.end(); fSubTask++) {
      auto task = dynamic_cast<JPetUserTask*>(fSubTask->get());
      std::string subtaskStatisticsName =
        task->getName() + std::string(" subtask ") + std::to_string(i) + std::string(" stats");
      fSubTasksStatistics[subtaskStatisticsName] = std::move(jpet_common_tools::make_unique<JPetStatistics>(*fStatistics));
      task->setStatistics(fSubTasksStatistics[subtaskStatisticsName].get());
      i++;
    }
  } else {
    WARNING("the subTask does not exist, so JPetStatistics not passed to it");
  }
  return true;
}

const JPetParamBank& JPetTaskIO::getParamBank()
{
  DEBUG("from JPetTaskIO");
  auto paramManager = fParams.getParamManager();
  assert(paramManager);
  return paramManager->getParamBank();
}

JPetParamManager& JPetTaskIO::getParamManager()
{
  DEBUG("JPetTaskIO");
  auto paramManager = fParams.getParamManager();
  static JPetParamManager NullManager(true);
  if (paramManager) {
    DEBUG("JPetParamManger returning normal parammanager");
    return *paramManager;
  } else {
    DEBUG("JPetParamManger returning NullManager ");
    return NullManager;
  }
}

std::string JPetTaskIO::getFirstSubTaskName() const
{
  std::string subTaskName;
  auto subtasks = getSubTasks();
  if (subtasks.size() > 0) {
    auto subTask = subtasks[0];
    if (subTask) {
      subTaskName = subTask->getName();
    }
  }
  return subTaskName;
}
<commit_msg>Small refactoring of JPetTaskIO<commit_after>/**
 *  @copyright Copyright 2018 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  @file JPetTaskIO.cpp
 */

#include "./JPetOptionsGenerator/JPetOptionsGeneratorTools.h"
#include "./JPetCommonTools/JPetCommonTools.h"
#include "./JPetTreeHeader/JPetTreeHeader.h"
#include "./JPetUserTask/JPetUserTask.h"
#include "./JPetTask/JPetTask.h"
#include "./JPetData/JPetData.h"
#include "./JPetLoggerInclude.h"
#include "JPetTaskIOTools.h"
#include "JPetTaskIO.h"
#include "./version.h"
#include <cassert>
#include <memory>

JPetTaskIO::JPetTaskIO(const char* name, const char* in_file_type, const char* out_file_type):
  JPetTask(name), fTaskInfo(in_file_type, out_file_type, "", false)
{
  if (std::string(out_file_type).empty()) {
    fIsOutput = false;
  }
  if (std::string(in_file_type).empty()) {
    fIsInput = false;
  }
}

JPetTaskIO::~JPetTaskIO() {}

bool JPetTaskIO::init(const JPetParams& params)
{
  using namespace jpet_options_tools;
  setParams(params);
  auto opts = fParams.getOptions();

  bool isOK = false;
  std::string inputFilename;
  std::string outFileFullPath;
  bool resetOutputPath = false;
  std::tie(isOK, inputFilename, outFileFullPath, resetOutputPath) = setInputAndOutputFile(opts);
  fTaskInfo.fOutFileFullPath = outFileFullPath;
  fTaskInfo.fResetOutputPath = resetOutputPath;

  auto subTaskName = getFirstSubTaskName();
  if (!isOK) {
    ERROR("Some error occured in setInputAndOutputFile, subtask name:" + subTaskName);
    return false;
  }

  if (isInput()) {
    if (!createInputObjects(inputFilename.c_str())) {
      ERROR("createInputObjects with the input file:" + inputFilename);
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
  }
  if (isOutput()) {
    if (!createOutputObjects(outFileFullPath.c_str())) {
      ERROR("createOutputObjects with the output file:" + outFileFullPath);
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
  }
  return true;
}

bool JPetTaskIO::run(const JPetDataInterface&)
{
  using namespace jpet_options_tools;
  if (fSubTasks.empty()) {
    ERROR("No subTask set");
    return false;
  }
  if (isInput()) {
    if (!fInputHandler) {
      ERROR("No inputHandler set");
      return false;
    }
  }
  for (const auto& pTask : fSubTasks) {
    auto subTaskName = pTask->getName();
    bool isOK = false;

    isOK = pTask->init(fParams);
    if (!isOK) {
      WARNING("In init() of:" + subTaskName + ". run()  and terminate() of this task will be skipped.");
      continue;
    }

    if (isInput()) {
      assert(fInputHandler);
      bool isProgressBarOn = isProgressBar(fParams.getOptions());
      isOK = fInputHandler->setEntryRange(fParams.getOptions());
      if (!isOK) {
        ERROR("Some error occured in setEntryRange");
        return false;
      }
      auto lastEvent = fInputHandler->getLastEntryNumber();
      assert(lastEvent >= 0);
      do {
        if (isProgressBarOn) {
          displayProgressBar(subTaskName, fInputHandler->getCurrentEntryNumber(), lastEvent);
        }
        JPetData event(fInputHandler->getEntry());
        isOK = pTask->run(event);
        if (!isOK) {
          ERROR("In run() of:" + subTaskName + ". ");
        }
        if (isOutput()) {
          if (!fOutputHandler->writeEventToFile(pTask.get())) {
            ERROR("Some problems occured, while writing the event to file.");
            return false;
          }
        }
      } while (fInputHandler->nextEntry());
    } else {
      JPetDataInterface dummyEvent;
      pTask->run(dummyEvent);
    }

    JPetParams subTaskParams;
    isOK = pTask->terminate(subTaskParams);
    if (!isOK) {
      ERROR("In terminate() of:" + subTaskName + ". ");
      return false;
    }
    fParams = mergeWithExtraParams(fParams, subTaskParams);
  }
  return true;
}

bool JPetTaskIO::terminate(JPetParams& output_params)
{
  auto subTaskName = getFirstSubTaskName();
  if (isOutput()) {
    auto newOpts = JPetTaskIOTools::setOutputOptions(fParams, fTaskInfo.fResetOutputPath, fTaskInfo.fOutFileFullPath);
    output_params = JPetParams(newOpts, fParams.getParamManagerAsShared());
  } else {
    output_params = fParams;
  }

  if (isOutput()) {
    if (!fHeader) {
      ERROR("Tree header is not set,");
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
    if (!fStatistics.get()) {
      ERROR("Statistics container with histograms is not set.");
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
    fOutputHandler->saveAndCloseOutput(getParamManager(), fHeader, fStatistics.get(), fSubTasksStatistics);
  }
  if (isInput()) {
    if (!fInputHandler) {
      ERROR("fInputHandler set to null.");
      ERROR("Subtask name:" + subTaskName);
      return false;
    }
    fInputHandler->closeInput();
  }
  return true;
}

void JPetTaskIO::addSubTask(std::unique_ptr<JPetTaskInterface> subTask)
{
  if (dynamic_cast<JPetUserTask*>(subTask.get()) == nullptr) {
    ERROR("JPetTaskIO currently only allows JPetUserTask as subtask");
  }
  fSubTasks.push_back(std::move(subTask));
}

void JPetTaskIO::displayProgressBar(std::string taskName, int currentEventNumber, int numberOfEvents) const
{
  return fProgressBar.display(taskName, currentEventNumber, numberOfEvents);
}

/**
 * @brief Currently this method passes "stopIteration_bool" option from subTask to fParams if present.
 */
JPetParams JPetTaskIO::mergeWithExtraParams(const JPetParams& oldParams, const JPetParams& extraParams) const
{
  using namespace jpet_options_tools;
  using namespace jpet_options_generator_tools;
  auto oldOpts = oldParams.getOptions();
  auto extraOpts = extraParams.getOptions();
  // @todo this is hardcoded and should be moved somewhere.
  const std::string stopIterationOptName = "stopIteration_bool";
  if (isOptionSet(extraOpts, stopIterationOptName)) {
    oldOpts[stopIterationOptName] = getOptionValue(extraOpts, stopIterationOptName);
  }
  return JPetParams(oldOpts, oldParams.getParamManagerAsShared());
}

void JPetTaskIO::setParams(const JPetParams& opts)
{
  fParams = opts;
}

JPetParams JPetTaskIO::getParams() const
{
  return fParams;
}

bool JPetTaskIO::isOutput() const
{
  return fIsOutput;
}

bool JPetTaskIO::isInput() const
{
  return fIsInput;
}

/**
 * @return (isOK, inputFile, outputFileFullPath, isResetOutputPath) based on provided options.
 * If isOK is set to false, that means that an error has occured.
 */
std::tuple<bool, std::string, std::string, bool> JPetTaskIO::setInputAndOutputFile(const OptsStrAny opts) const
{
  // We cannot remove this method completely and leave the one from JPetTaskIOTools, because it is overloaded in JPetScopeLoader class.
  return JPetTaskIOTools::setInputAndOutputFile(opts, fTaskInfo.fResetOutputPath, fTaskInfo.fInFileType, fTaskInfo.fOutFileType);
}

bool JPetTaskIO::createInputObjects(const char* inputFilename)
{
  fInputHandler = jpet_common_tools::make_unique<JPetInputHandler>();
  return fInputHandler->openInput(inputFilename, fParams);
}

bool JPetTaskIO::createOutputObjects(const char* outputFilename)
{
  if (!isOutput()) {
    ERROR("isOutput set to false and you are trying to createOutputObjects");
    return false;
  }
  fOutputHandler = jpet_common_tools::make_unique<JPetOutputHandler>(outputFilename);
  if (!fOutputHandler) {
    ERROR("OutputHandler is not set, cannot creat output file.");
    return false;
  }
  using namespace jpet_options_tools;
  auto options = fParams.getOptions();

  if (FileTypeChecker::getInputFileType(options) == FileTypeChecker::kHldRoot ||
      FileTypeChecker::getInputFileType(options) == FileTypeChecker::kMCGeant ) {

    fHeader = new JPetTreeHeader(getRunNumber(options));
    fHeader->setFrameworkVersion(FRAMEWORK_VERSION);
    fHeader->setFrameworkRevision(FRAMEWORK_REVISION);

    // add general info to the Tree header
    fHeader->setBaseFileName(getInputFile(options).c_str());
  } else {
    if (isInput()) {
      // read the header from the previous analysis stage
      fHeader = fInputHandler->getHeaderClone();
    } else {
      ERROR("We are trying to load Tree Header from the input file, and no input is set.");
      return false;
    }
  }

  fStatistics = jpet_common_tools::make_unique<JPetStatistics>();

  // add info about this module to the processing stages' history in Tree header
  for (auto fSubTask = fSubTasks.begin(); fSubTask != fSubTasks.end(); fSubTask++) {
    auto task = dynamic_cast<JPetUserTask*>((*fSubTask).get());
    fHeader->addStageInfo(task->getName(), "", 0,
                          JPetCommonTools::getTimeString());
  }

  if (!fSubTasks.empty()) {
    int i = 0;
    for (auto fSubTask = fSubTasks.begin(); fSubTask != fSubTasks.end(); fSubTask++) {
      auto task = dynamic_cast<JPetUserTask*>(fSubTask->get());
      std::string subtaskStatisticsName =
        task->getName() + std::string(" subtask ") + std::to_string(i) + std::string(" stats");
      fSubTasksStatistics[subtaskStatisticsName] = std::move(jpet_common_tools::make_unique<JPetStatistics>(*fStatistics));
      task->setStatistics(fSubTasksStatistics[subtaskStatisticsName].get());
      i++;
    }
  } else {
    WARNING("the subTask does not exist, so JPetStatistics not passed to it");
  }
  return true;
}

const JPetParamBank& JPetTaskIO::getParamBank()
{
  DEBUG("from JPetTaskIO");
  auto paramManager = fParams.getParamManager();
  assert(paramManager);
  return paramManager->getParamBank();
}

JPetParamManager& JPetTaskIO::getParamManager()
{
  DEBUG("JPetTaskIO");
  auto paramManager = fParams.getParamManager();
  static JPetParamManager NullManager(true);
  if (paramManager) {
    DEBUG("JPetParamManger returning normal parammanager");
    return *paramManager;
  } else {
    DEBUG("JPetParamManger returning NullManager ");
    return NullManager;
  }
}

std::string JPetTaskIO::getFirstSubTaskName() const
{
  std::string subTaskName;
  auto subtasks = getSubTasks();
  if (subtasks.size() > 0) {
    auto subTask = subtasks[0];
    if (subTask) {
      subTaskName = subTask->getName();
    }
  }
  return subTaskName;
}
<|endoftext|>


<commit_before>#include <taichi/common/util.h>
#include <taichi/common/task.h>
#include <taichi/visual/gui.h>
#include "sound.h"

TC_NAMESPACE_BEGIN

constexpr int n = 100;
constexpr real room_size = 10.0_f;
constexpr real dx = room_size / n;
constexpr real c = 340;
constexpr real alpha = 0.0001;

Array2D<real> p, q, r;

void advance(real dt) {
  std::swap(p.data, q.data);
  std::swap(q.data, r.data);
  r.reset_zero();
  constexpr real inv_dx2 = pow<2>(1.0_f / dx);
  for (int i = 1; i < n - 1; i++) {
    for (int j = 1; j < n - 1; j++) {
      real laplacian_p = inv_dx2 * (p[i - 1][j] + p[i][j - 1] + p[i + 1][j] +
                                    p[i][j + 1] - 4 * p[i][j]);
      real laplacian_q = inv_dx2 * (q[i - 1][j] + q[i][j - 1] + q[i + 1][j] +
                                    q[i][j + 1] - 4 * q[i][j]);

      r[i][j] = 2 * q[i][j] + (c * c * dt * dt + c * alpha * dt) * laplacian_q -
                p[i][j] - c * alpha * dt * laplacian_p;
    }
  }
}

auto sound = []() {
  int window_size = 800;
  int scale = window_size / n;
  q.initialize(Vector2i(n));
  p = r = q;
  GUI gui("Sound simulation", Vector2i(window_size));
  real t = 0, dt = (std::sqrt(alpha * alpha + dx * dx / 3) - alpha) / c;
  // p[n / 2][n / 2] = std::sin(t);
  FILE *f = fopen("data/wave.txt", "r");
  WaveFile wav_file("output.wav");
  dt = 1_f / 44100;
  TC_P(dt);

  for (int T = 0; T < 1000; T++) {
    for (int i = 0; i < 2000; i++) {
      real left, right;
      fscanf(f, "%f%f", &left, &right);
      advance(dt);
      r[n / 4][n / 2] = (left + right) / 65536.0;
      t += dt;
      wav_file.add_sound(dt, r[n / 4 + 4][n / 2]);
      // wav_file.add_sound(dt, std::sin(t * 10000));
    }
    for (int i = 0; i < window_size; i++) {
      for (int j = 0; j < window_size; j++) {
        auto c = p[i / scale][j / scale];
        gui.get_canvas().img[i][j] = Vector3(c + 0.5_f);
      }
    }
    gui.update();
    if (T % 100 == 0)
      wav_file.flush();
  }
};

TC_REGISTER_TASK(sound);

TC_NAMESPACE_END
<commit_msg>Changed to 3D<commit_after>#include <taichi/common/util.h>
#include <taichi/common/task.h>
#include <taichi/visual/gui.h>
#include "sound.h"

TC_NAMESPACE_BEGIN

constexpr int n = 30;
constexpr real room_size = 10.0_f;
constexpr real dx = room_size / n;
constexpr real c = 340;
constexpr real alpha = 0.001;

Array3D<real> p, q, r;

void advance(real dt) {
  std::swap(p.data, q.data);
  std::swap(q.data, r.data);
  r.reset_zero();
  constexpr real inv_dx2 = pow<2>(1.0_f / dx);
  for (int i = 1; i < n - 1; i++) {
    for (int j = 1; j < n - 1; j++) {
      for (int k = 1; k < n - 1; k++) {
        real laplacian_p =
            inv_dx2 *
            (p[i - 1][j][k] + p[i][j - 1][k] + p[i + 1][j][k] + p[i][j + 1][k] +
             p[i][j][k + 1] + p[i][j][k - 1] - 6 * p[i][j][k]);
        real laplacian_q =
            inv_dx2 *
            (q[i - 1][j][k] + q[i][j - 1][k] + q[i + 1][j][k] + q[i][j + 1][k] +
             q[i][j][k + 1] + q[i][j][k - 1] - 6 * q[i][j][k]);

        r[i][j][k] = 2 * q[i][j][k] +
                     (c * c * dt * dt + c * alpha * dt) * laplacian_q -
                     p[i][j][k] - c * alpha * dt * laplacian_p;
      }
    }
  }
}

auto sound = []() {
  int window_size = 800;
  int scale = window_size / n;
  q.initialize(Vector3i(n));
  p = r = q;
  GUI gui("Sound simulation", Vector2i(window_size));
  real t = 0, dt = (std::sqrt(alpha * alpha + dx * dx / 3) - alpha) / c;
  // p[n / 2][n / 2] = std::sin(t);
  FILE *f = fopen("data/wave.txt", "r");
  WaveFile wav_file("output.wav");
  dt = 1_f / 44100;
  TC_P(dt);

  r[n / 2][n / 2][n / 2] = 1;

  for (int T = 0; T < 1000; T++) {
    for (int i = 0; i < 5; i++) {
      real left, right;
      fscanf(f, "%f%f", &left, &right);
      advance(dt);
      // r[n / 4][n / 2] = (left + right) / 65536.0;
      t += dt;
      wav_file.add_sound(dt, r[n / 4 + 4][n / 2][n / 2]);
      // wav_file.add_sound(dt, std::sin(t * 10000));
    }
    for (int i = 0; i < window_size; i++) {
      for (int j = 0; j < window_size; j++) {
        auto c = p[i / scale][j / scale][n / 2];
        gui.get_canvas().img[i][j] = Vector3(c + 0.5_f);
      }
    }
    gui.update();
    if (T % 100 == 0)
      wav_file.flush();
  }
};

TC_REGISTER_TASK(sound);

TC_NAMESPACE_END
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.

#include <iostream>
#include <vector>
#include <algorithm>

// Google Test
#include <gtest/gtest.h>

// HIP API
#include <hip/hip_runtime.h>
// hipCUB API
#include <hipcub.hpp>

#include "test_utils.hpp"

#define HIP_CHECK(error)         \
    ASSERT_EQ(static_cast<hipError_t>(error),hipSuccess)

// Params for tests
template<
    class InputType,
    class OutputType = InputType
>
struct DeviceReduceParams
{
    using input_type = InputType;
    using output_type = OutputType;
};

// ---------------------------------------------------------
// Test for reduction ops taking single input value
// ---------------------------------------------------------

template<class Params>
class HipcubDeviceReduceTests : public ::testing::Test
{
public:
    using input_type = typename Params::input_type;
    using output_type = typename Params::output_type;
    #ifdef HIPCUB_CUB_API
    const bool debug_synchronous = false;
    #else
    const bool debug_synchronous = !false;
    #endif
};

typedef ::testing::Types<
    // -----------------------------------------------------------------------
    //
    // -----------------------------------------------------------------------
    DeviceReduceParams<int>,
    DeviceReduceParams<unsigned long>,
    DeviceReduceParams<short>,
    DeviceReduceParams<int>
> HipcubDeviceReduceTestsParams;

std::vector<size_t> get_sizes()
{
    std::vector<size_t> sizes = {
        1, 10, 53, 211,
        1024, 2048, 5096,
        34567, (1 << 17) - 1220
    };
    const std::vector<size_t> random_sizes = test_utils::get_random_data<size_t>(2, 1, 16384);
    sizes.insert(sizes.end(), random_sizes.begin(), random_sizes.end());
    std::sort(sizes.begin(), sizes.end());
    return sizes;
}

TYPED_TEST_CASE(HipcubDeviceReduceTests, HipcubDeviceReduceTestsParams);

TYPED_TEST(HipcubDeviceReduceTests, Reduce)
{
    using T = typename TestFixture::input_type;
    using U = typename TestFixture::output_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, 1, 100);
        std::vector<U> output(1, 0);

        T * d_input;
        U * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(U)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Calculate expected results on host
        U expected = std::accumulate(input.begin(), input.end(), 0);

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::Sum(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::Sum(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(U),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        auto diff = std::max<U>(std::abs(0.01f * expected), U(0.01f));
        if(std::is_integral<U>::value) diff = 0;
        ASSERT_NEAR(output[0], expected, diff);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}

TYPED_TEST(HipcubDeviceReduceTests, ReduceMinimum)
{
    using T = typename TestFixture::input_type;
    using U = typename TestFixture::output_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, 1, 100);
        std::vector<U> output(1, 0);

        T * d_input;
        U * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(U)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        hipcub::Min min_op;
        // Calculate expected results on host
        U expected = std::accumulate(
            input.begin(), input.end(),
            std::numeric_limits<U>::max(), min_op
        );

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::Min(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::Min(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(U),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        ASSERT_EQ(output[0], expected);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}

TYPED_TEST(HipcubDeviceReduceTests, ReduceArgMinimum)
{
    using T = typename TestFixture::input_type;
    using Iterator = typename hipcub::ArgIndexInputIterator<T*, int>;
    using key_value = typename Iterator::value_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, 1, 200);
        std::vector<key_value> output(1);

        T * d_input;
        key_value * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(key_value)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        const key_value max(1, std::numeric_limits<T>::max());

        // Calculate expected results on host
        Iterator x(input.data());
        key_value expected = std::accumulate(x, x + size, max, hipcub::ArgMin());

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMin(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMin(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(key_value),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        ASSERT_EQ(output[0].key, expected.key);
        ASSERT_EQ(output[0].value, expected.value);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}

TYPED_TEST(HipcubDeviceReduceTests, ReduceArgMaximum)
{
    using T = typename TestFixture::input_type;
    using Iterator = typename hipcub::ArgIndexInputIterator<T*, int>;
    using key_value = typename Iterator::value_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, -100, 100);
        std::vector<key_value> output(1);

        T * d_input;
        key_value * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(key_value)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        const key_value max(1, std::numeric_limits<T>::lowest());

        // Calculate expected results on host
        Iterator x(input.data());
        key_value expected = std::accumulate(x, x + size, max, hipcub::ArgMax());

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMax(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMax(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(key_value),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        ASSERT_EQ(output[0].key, expected.key);
        ASSERT_EQ(output[0].value, expected.value);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}
<commit_msg>Remove integer conversion warning<commit_after>// MIT License
//
// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.

#include <iostream>
#include <vector>
#include <algorithm>

// Google Test
#include <gtest/gtest.h>

// HIP API
#include <hip/hip_runtime.h>
// hipCUB API
#include <hipcub.hpp>

#include "test_utils.hpp"

#define HIP_CHECK(error)         \
    ASSERT_EQ(static_cast<hipError_t>(error),hipSuccess)

// Params for tests
template<
    class InputType,
    class OutputType = InputType
>
struct DeviceReduceParams
{
    using input_type = InputType;
    using output_type = OutputType;
};

// ---------------------------------------------------------
// Test for reduction ops taking single input value
// ---------------------------------------------------------

template<class Params>
class HipcubDeviceReduceTests : public ::testing::Test
{
public:
    using input_type = typename Params::input_type;
    using output_type = typename Params::output_type;
    #ifdef HIPCUB_CUB_API
    const bool debug_synchronous = false;
    #else
    const bool debug_synchronous = !false;
    #endif
};

typedef ::testing::Types<
    // -----------------------------------------------------------------------
    //
    // -----------------------------------------------------------------------
    DeviceReduceParams<int>,
    DeviceReduceParams<unsigned long>,
    DeviceReduceParams<short>,
    DeviceReduceParams<int>
> HipcubDeviceReduceTestsParams;

std::vector<size_t> get_sizes()
{
    std::vector<size_t> sizes = {
        1, 10, 53, 211,
        1024, 2048, 5096,
        34567, (1 << 17) - 1220
    };
    const std::vector<size_t> random_sizes = test_utils::get_random_data<size_t>(2, 1, 16384);
    sizes.insert(sizes.end(), random_sizes.begin(), random_sizes.end());
    std::sort(sizes.begin(), sizes.end());
    return sizes;
}

TYPED_TEST_CASE(HipcubDeviceReduceTests, HipcubDeviceReduceTestsParams);

TYPED_TEST(HipcubDeviceReduceTests, Reduce)
{
    using T = typename TestFixture::input_type;
    using U = typename TestFixture::output_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, 1, 100);
        std::vector<U> output(1, 0);

        T * d_input;
        U * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(U)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Calculate expected results on host
        U expected = std::accumulate(input.begin(), input.end(), 0);

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::Sum(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::Sum(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(U),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        auto diff = std::max<U>(std::abs(0.01f * expected), U(0.01f));
        if(std::is_integral<U>::value) diff = 0;
        ASSERT_NEAR(output[0], expected, diff);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}

TYPED_TEST(HipcubDeviceReduceTests, ReduceMinimum)
{
    using T = typename TestFixture::input_type;
    using U = typename TestFixture::output_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, 1, 100);
        std::vector<U> output(1, 0);

        T * d_input;
        U * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(U)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        hipcub::Min min_op;
        // Calculate expected results on host
        U expected = std::accumulate(
            input.begin(), input.end(),
            std::numeric_limits<U>::max(), min_op
        );

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::Min(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::Min(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(U),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        ASSERT_EQ(output[0], expected);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}

TYPED_TEST(HipcubDeviceReduceTests, ReduceArgMinimum)
{
    using T = typename TestFixture::input_type;
    using Iterator = typename hipcub::ArgIndexInputIterator<T*, int>;
    using key_value = typename Iterator::value_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, 1, 200);
        std::vector<key_value> output(1);

        T * d_input;
        key_value * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(key_value)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        const key_value max(1, std::numeric_limits<T>::max());

        // Calculate expected results on host
        Iterator x(input.data());
        key_value expected = std::accumulate(x, x + size, max, hipcub::ArgMin());

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMin(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMin(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(key_value),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        ASSERT_EQ(output[0].key, expected.key);
        ASSERT_EQ(output[0].value, expected.value);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}

TYPED_TEST(HipcubDeviceReduceTests, ReduceArgMaximum)
{
    using T = typename TestFixture::input_type;
    using Iterator = typename hipcub::ArgIndexInputIterator<T*, int>;
    using key_value = typename Iterator::value_type;
    const bool debug_synchronous = TestFixture::debug_synchronous;

    const std::vector<size_t> sizes = get_sizes();
    for(auto size : sizes)
    {
        // HIP
        hipStream_t stream = 0; // default
        HIP_CHECK(hipStreamCreate(&stream));

        SCOPED_TRACE(testing::Message() << "with size = " << size);

        // Generate data
        std::vector<T> input = test_utils::get_random_data<T>(size, T(-100), T(100));
        std::vector<key_value> output(1);

        T * d_input;
        key_value * d_output;
        HIP_CHECK(hipMalloc(&d_input, input.size() * sizeof(T)));
        HIP_CHECK(hipMalloc(&d_output, output.size() * sizeof(key_value)));
        HIP_CHECK(
            hipMemcpy(
                d_input, input.data(),
                input.size() * sizeof(T),
                hipMemcpyHostToDevice
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        const key_value max(1, std::numeric_limits<T>::lowest());

        // Calculate expected results on host
        Iterator x(input.data());
        key_value expected = std::accumulate(x, x + size, max, hipcub::ArgMax());

        // temp storage
        size_t temp_storage_size_bytes;
        void * d_temp_storage = nullptr;
        // Get size of d_temp_storage
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMax(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );

        // temp_storage_size_bytes must be >0
        ASSERT_GT(temp_storage_size_bytes, 0U);

        // allocate temporary storage
        HIP_CHECK(hipMalloc(&d_temp_storage, temp_storage_size_bytes));
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Run
        HIP_CHECK(
            hipcub::DeviceReduce::ArgMax(
                d_temp_storage, temp_storage_size_bytes,
                d_input, d_output, input.size(),
                stream, debug_synchronous
            )
        );
        HIP_CHECK(hipPeekAtLastError());
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Copy output to host
        HIP_CHECK(
            hipMemcpy(
                output.data(), d_output,
                output.size() * sizeof(key_value),
                hipMemcpyDeviceToHost
            )
        );
        HIP_CHECK(hipDeviceSynchronize());
        HIP_CHECK(hipStreamSynchronize(stream));

        // Check if output values are as expected
        ASSERT_EQ(output[0].key, expected.key);
        ASSERT_EQ(output[0].value, expected.value);

        hipFree(d_input);
        hipFree(d_output);
        hipFree(d_temp_storage);

        // HIP stream
        HIP_CHECK(hipStreamDestroy(stream));
    }
}
<|endoftext|>


<commit_before>//===- MapFile.cpp --------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the -Map option. It shows lists in order and
// hierarchically the output sections, input sections, input files and
// symbol:
//
//   Address  Size     Align Out     In      Symbol
//   00201000 00000015     4 .text
//   00201000 0000000e     4         test.o:(.text)
//   0020100e 00000000     0                 local
//   00201005 00000000     0                 f(int)
//
//===----------------------------------------------------------------------===//

#include "MapFile.h"
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Threads.h"

#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf;

typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>>
    SymbolMapTy;

// Print out the first three columns of a line.
static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
                        uint64_t Align) {
  int W = Config->Is64 ? 16 : 8;
  OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
}

static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }

// Returns a list of all symbols that we want to print out.
template <class ELFT> static std::vector<DefinedRegular *> getSymbols() {
  std::vector<DefinedRegular *> V;
  for (ObjFile<ELFT> *File : ObjFile<ELFT>::Instances)
    for (SymbolBody *B : File->getSymbols())
      if (B->File == File && !B->isSection())
        if (auto *Sym = dyn_cast<DefinedRegular>(B))
          if (Sym->Section && Sym->Section->Live)
            V.push_back(Sym);
  return V;
}

// Returns a map from sections to their symbols.
static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
  SymbolMapTy Ret;
  for (DefinedRegular *S : Syms)
    Ret[S->Section].push_back(S);

  // Sort symbols by address. We want to print out symbols in the
  // order in the output file rather than the order they appeared
  // in the input files.
  for (auto &It : Ret) {
    SmallVectorImpl<DefinedRegular *> &V = It.second;
    std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
      return A->getVA() < B->getVA();
    });
  }
  return Ret;
}

// Construct a map from symbols to their stringified representations.
// Demangling symbols (which is what toString() does) is slow, so
// we do that in batch using parallel-for.
template <class ELFT>
static DenseMap<DefinedRegular *, std::string>
getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
  std::vector<std::string> Str(Syms.size());
  parallelForEachN(0, Syms.size(), [&](size_t I) {
    raw_string_ostream OS(Str[I]);
    writeHeader(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(), 0);
    OS << indent(2) << toString(*Syms[I]);
  });

  DenseMap<DefinedRegular *, std::string> Ret;
  for (size_t I = 0, E = Syms.size(); I < E; ++I)
    Ret[Syms[I]] = std::move(Str[I]);
  return Ret;
}

template <class ELFT> void elf::writeMapFile() {
  if (Config->MapFile.empty())
    return;

  // Open a map file for writing.
  std::error_code EC;
  raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
  if (EC) {
    error("cannot open " + Config->MapFile + ": " + EC.message());
    return;
  }

  // Collect symbol info that we want to print out.
  std::vector<DefinedRegular *> Syms = getSymbols<ELFT>();
  SymbolMapTy SectionSyms = getSectionSyms(Syms);
  DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms);

  // Print out the header line.
  int W = ELFT::Is64Bits ? 16 : 8;
  OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
     << " Align Out     In      Symbol\n";

  // Print out file contents.
  for (OutputSection *OSec : OutputSections) {
    writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment);
    OS << OSec->Name << '\n';

    // Dump symbols for each input section.
    for (BaseCommand *Base : OSec->Commands) {
      auto *ISD = dyn_cast<InputSectionDescription>(Base);
      if (!ISD)
        continue;
      for (InputSection *IS : ISD->Sections) {
        writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
                    IS->Alignment);
        OS << indent(1) << toString(IS) << '\n';
        for (DefinedRegular *Sym : SectionSyms[IS])
          OS << SymStr[Sym] << '\n';
      }
    }
  }
}

template void elf::writeMapFile<ELF32LE>();
template void elf::writeMapFile<ELF32BE>();
template void elf::writeMapFile<ELF64LE>();
template void elf::writeMapFile<ELF64BE>();
<commit_msg>Simplify. NFC.<commit_after>//===- MapFile.cpp --------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the -Map option. It shows lists in order and
// hierarchically the output sections, input sections, input files and
// symbol:
//
//   Address  Size     Align Out     In      Symbol
//   00201000 00000015     4 .text
//   00201000 0000000e     4         test.o:(.text)
//   0020100e 00000000     0                 local
//   00201005 00000000     0                 f(int)
//
//===----------------------------------------------------------------------===//

#include "MapFile.h"
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Threads.h"

#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf;

typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>>
    SymbolMapTy;

// Print out the first three columns of a line.
static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
                        uint64_t Align) {
  int W = Config->Is64 ? 16 : 8;
  OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
}

static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }

// Returns a list of all symbols that we want to print out.
template <class ELFT> static std::vector<DefinedRegular *> getSymbols() {
  std::vector<DefinedRegular *> V;
  for (ObjFile<ELFT> *File : ObjFile<ELFT>::Instances)
    for (SymbolBody *B : File->getSymbols())
      if (auto *DR = dyn_cast<DefinedRegular>(B))
        if (DR->File == File && !DR->isSection() && DR->Section &&
            DR->Section->Live)
          V.push_back(DR);
  return V;
}

// Returns a map from sections to their symbols.
static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
  SymbolMapTy Ret;
  for (DefinedRegular *S : Syms)
    Ret[S->Section].push_back(S);

  // Sort symbols by address. We want to print out symbols in the
  // order in the output file rather than the order they appeared
  // in the input files.
  for (auto &It : Ret) {
    SmallVectorImpl<DefinedRegular *> &V = It.second;
    std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
      return A->getVA() < B->getVA();
    });
  }
  return Ret;
}

// Construct a map from symbols to their stringified representations.
// Demangling symbols (which is what toString() does) is slow, so
// we do that in batch using parallel-for.
template <class ELFT>
static DenseMap<DefinedRegular *, std::string>
getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
  std::vector<std::string> Str(Syms.size());
  parallelForEachN(0, Syms.size(), [&](size_t I) {
    raw_string_ostream OS(Str[I]);
    writeHeader(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(), 0);
    OS << indent(2) << toString(*Syms[I]);
  });

  DenseMap<DefinedRegular *, std::string> Ret;
  for (size_t I = 0, E = Syms.size(); I < E; ++I)
    Ret[Syms[I]] = std::move(Str[I]);
  return Ret;
}

template <class ELFT> void elf::writeMapFile() {
  if (Config->MapFile.empty())
    return;

  // Open a map file for writing.
  std::error_code EC;
  raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
  if (EC) {
    error("cannot open " + Config->MapFile + ": " + EC.message());
    return;
  }

  // Collect symbol info that we want to print out.
  std::vector<DefinedRegular *> Syms = getSymbols<ELFT>();
  SymbolMapTy SectionSyms = getSectionSyms(Syms);
  DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms);

  // Print out the header line.
  int W = ELFT::Is64Bits ? 16 : 8;
  OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
     << " Align Out     In      Symbol\n";

  // Print out file contents.
  for (OutputSection *OSec : OutputSections) {
    writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment);
    OS << OSec->Name << '\n';

    // Dump symbols for each input section.
    for (BaseCommand *Base : OSec->Commands) {
      auto *ISD = dyn_cast<InputSectionDescription>(Base);
      if (!ISD)
        continue;
      for (InputSection *IS : ISD->Sections) {
        writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
                    IS->Alignment);
        OS << indent(1) << toString(IS) << '\n';
        for (DefinedRegular *Sym : SectionSyms[IS])
          OS << SymStr[Sym] << '\n';
      }
    }
  }
}

template void elf::writeMapFile<ELF32LE>();
template void elf::writeMapFile<ELF32BE>();
template void elf::writeMapFile<ELF64LE>();
template void elf::writeMapFile<ELF64BE>();
<|endoftext|>