<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2012 Rene Kuettner <rene@bitkanal.net>
//

#include "OrbiterSatellitesModel.h"

#include <QtCore/QUrl>

#include "MarbleDebug.h"
#include "MarbleClock.h"
#include "MarbleDirs.h"

#include "mex/planetarySats.h"

#include "OrbiterSatellitesItem.h"

namespace Marble {

OrbiterSatellitesModel::OrbiterSatellitesModel(
    GeoDataTreeModel *treeModel,
    const PluginManager *pluginManager,
    const MarbleClock *clock )
    : TrackerPluginModel( treeModel, pluginManager ),
      m_clock( clock ),
      m_lcPlanet( QString() ),
      m_catalogs( QString() )
{
    connect( m_clock, SIGNAL( timeChanged() ), this, SLOT( update() ) );
}

OrbiterSatellitesModel::~OrbiterSatellitesModel()
{
}

void OrbiterSatellitesModel::setPlanet( const QString &planetId )
{
    if( m_lcPlanet != planetId ) {

        mDebug() << "Planet changed from" << m_lcPlanet << "to" << planetId;
        m_lcPlanet = planetId;

        // reload catalogs
        foreach( const QString &catalog, m_catalogs ) {
            downloadFile( QUrl( catalog ), catalog.section( '/', -1 ) );
        }
    }
}

void OrbiterSatellitesModel::parseFile( const QString &id,
                                        const QByteArray &file )
{
    mDebug() << "Reading orbiter catalog from:" << id;
    QTextStream ts(file);

    QString planet( m_lcPlanet.left(1).toUpper() + m_lcPlanet.mid(1) );
    char *cplanet = planet.toLocal8Bit().data();

    beginUpdateItems();

    QString line = ts.readLine();
    for( ; !line.isNull(); line = ts.readLine() ) {

        if( line.trimmed().indexOf( "#" ) == 0) {
            continue;
        }

        QStringList elms = line.split(", ");

        if( elms.size() != 13 ) {
            mDebug() << "Skipping line:" << elms << "(" << line << ")";
            continue;
        }

        QString name = QString("%1 (%2)").arg( elms[0], elms[1] );
        QString planet( elms[2] );

        if( planet.toLower() != m_lcPlanet ) {
            continue;
        }

        mDebug() << "Loading orbiter object:" << name;

        PlanetarySats *planSat = new PlanetarySats();

        planSat->setStateVector( elms[6].toFloat() - 2400000.5,
             elms[7].toFloat(),  elms[8].toFloat(),  elms[9].toFloat(),
            elms[10].toFloat(), elms[11].toFloat(), elms[12].toFloat() );

        planSat->setPlanet( cplanet );
        planSat->stateToKepler();

        addItem( new OrbiterSatellitesItem( name, planSat, m_clock ) );
    }

    endUpdateItems();
}

void OrbiterSatellitesModel::downloadFile(const QUrl &url, const QString &id)
{
    // add url to list of known catalogs
    if( !m_catalogs.contains( url.toString() ) ) {
        m_catalogs.append( url.toString() );
    }

    TrackerPluginModel::downloadFile( url, id );
}

} // namespace Marble

#include "OrbiterSatellitesModel.moc"

<commit_msg>SatellitesPlugin: clear satellites when switching planet<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2012 Rene Kuettner <rene@bitkanal.net>
//

#include "OrbiterSatellitesModel.h"

#include <QtCore/QUrl>

#include "MarbleDebug.h"
#include "MarbleClock.h"
#include "MarbleDirs.h"

#include "mex/planetarySats.h"

#include "OrbiterSatellitesItem.h"

namespace Marble {

OrbiterSatellitesModel::OrbiterSatellitesModel(
    GeoDataTreeModel *treeModel,
    const PluginManager *pluginManager,
    const MarbleClock *clock )
    : TrackerPluginModel( treeModel, pluginManager ),
      m_clock( clock ),
      m_lcPlanet( QString() ),
      m_catalogs( QString() )
{
    connect( m_clock, SIGNAL( timeChanged() ), this, SLOT( update() ) );
}

OrbiterSatellitesModel::~OrbiterSatellitesModel()
{
}

void OrbiterSatellitesModel::setPlanet( const QString &planetId )
{
    if( m_lcPlanet != planetId ) {

        mDebug() << "Planet changed from" << m_lcPlanet << "to" << planetId;
        m_lcPlanet = planetId;

        // reload catalogs
        foreach( const QString &catalog, m_catalogs ) {
            downloadFile( QUrl( catalog ), catalog.section( '/', -1 ) );
        }
    }
}

void OrbiterSatellitesModel::parseFile( const QString &id,
                                        const QByteArray &file )
{
    mDebug() << "Reading orbiter catalog from:" << id;
    QTextStream ts(file);

    QString planet( m_lcPlanet.left(1).toUpper() + m_lcPlanet.mid(1) );
    char *cplanet = planet.toLocal8Bit().data();

    clear();

    beginUpdateItems();

    QString line = ts.readLine();
    for( ; !line.isNull(); line = ts.readLine() ) {

        if( line.trimmed().indexOf( "#" ) == 0) {
            continue;
        }

        QStringList elms = line.split(", ");

        if( elms.size() != 13 ) {
            mDebug() << "Skipping line:" << elms << "(" << line << ")";
            continue;
        }

        QString name = QString("%1 (%2)").arg( elms[0], elms[1] );
        QString planet( elms[2] );

        if( planet.toLower() != m_lcPlanet ) {
            continue;
        }

        mDebug() << "Loading orbiter object:" << name;

        PlanetarySats *planSat = new PlanetarySats();

        planSat->setStateVector( elms[6].toFloat() - 2400000.5,
             elms[7].toFloat(),  elms[8].toFloat(),  elms[9].toFloat(),
            elms[10].toFloat(), elms[11].toFloat(), elms[12].toFloat() );

        planSat->setPlanet( cplanet );
        planSat->stateToKepler();

        addItem( new OrbiterSatellitesItem( name, planSat, m_clock ) );
    }

    endUpdateItems();
}

void OrbiterSatellitesModel::downloadFile(const QUrl &url, const QString &id)
{
    // add url to list of known catalogs
    if( !m_catalogs.contains( url.toString() ) ) {
        m_catalogs.append( url.toString() );
    }

    TrackerPluginModel::downloadFile( url, id );
}

} // namespace Marble

#include "OrbiterSatellitesModel.moc"

<|endoftext|>


<commit_before>#include "RichHdrWrapper.h"
#include "PEFile.h"
#include <iostream>

bool RichHdrWrapper::wrap()
{
    this->richSign = m_PE->getRichHeaderSign();
    this->dansHdr = m_PE->getRichHeaderBgn(richSign);
    this->compIdCounter = this->compIdCount();
    return true;
}

void* RichHdrWrapper::getPtr()
{
    RICH_SIGNATURE* richSign = m_PE->getRichHeaderSign();
    if (!richSign) {
        return nullptr;
    }
    RICH_DANS_HEADER* dansHdr = m_PE->getRichHeaderBgn(richSign);
    if (!dansHdr) {
        return nullptr;
    }
    return (void*)dansHdr;
}

size_t RichHdrWrapper::compIdCount()
{
    if (!this->richSign || !this->dansHdr) {
        return 0;
    }
    const RICH_DANS_HEADER dans_empty = { 0 };
    const bufsize_t dif = ((ULONGLONG)richSign - (ULONGLONG)dansHdr) - (sizeof(dans_empty.dansId) + sizeof(dans_empty.cPad));
    bufsize_t count = dif / sizeof(RICH_COMP_ID);
    return (size_t) count;
}

bufsize_t RichHdrWrapper::getSize()
{
    if (!this->richSign || !this->dansHdr) {
        return 0;
    }
    const size_t cnt = this->compIdCounter - 1;
    const bufsize_t dif = sizeof(RICH_DANS_HEADER) + sizeof(RICH_SIGNATURE) + (sizeof(RICH_COMP_ID) * cnt);
    return dif;
}

size_t RichHdrWrapper::getFieldsCount()
{
    if (getSize() == 0) return 0;
    return this->compIdCounter + FIELD_COUNTER - 1;
}

void* RichHdrWrapper::getFieldPtr(size_t fieldId, size_t subField)
{
    if (!this->richSign || !this->dansHdr) {
        return 0;
    }

    const size_t cnt = this->compIdCounter - 1;
    switch (fieldId) {
         case DANS_ID: return (void*) &dansHdr->dansId;
         case CPAD0: return (void*) &dansHdr->cPad[0];
         case CPAD1: return (void*) &dansHdr->cPad[1];
         case CPAD2: return (void*) &dansHdr->cPad[2];
         //case COMP_ID_1: return (void*) &dansHdr->compId;
         //case RICH_ID: return (void*) &richSign->richId;
         //case CHECKSUM: return (void*) &richSign->checksum;
    }
    if (fieldId >= COMP_ID_1 && fieldId <= COMP_ID_1 + cnt)
    {
        size_t compIdNum = fieldId - COMP_ID_1;
        return (void*)(ULONGLONG(&dansHdr->compId) + (sizeof(RICH_COMP_ID)*compIdNum));
    }
    if (fieldId == RICH_ID + cnt) return (void*) &richSign->richId;
    if (fieldId == CHECKSUM + cnt) return (void*) &richSign->checksum;
    return (void*) dansHdr;
}

QString RichHdrWrapper::getFieldName(size_t fieldId)
{
    if (!this->richSign || !this->dansHdr) {
        return "";
    }
    const size_t cnt = this->compIdCounter - 1;

    switch (fieldId) {
         case DANS_ID: return("DanS ID");
         case CPAD0: case CPAD1: case CPAD2:  return ("Checksumed padding");
    }
    if (fieldId >= COMP_ID_1 && fieldId <= COMP_ID_1 + cnt)
    {
        return("Comp ID");
    }
    if (fieldId == RICH_ID + cnt) return("Rich ID");
    if (fieldId == CHECKSUM + cnt) return("Checksum");
    return "";
}

Executable::addr_type RichHdrWrapper::containsAddrType(uint32_t fieldId, uint32_t subField)
{
    return Executable::NOT_ADDR;
}

QString RichHdrWrapper::translateFieldContent(size_t fieldId)
{
    if (!this->richSign || !this->dansHdr) {
        return "";
    }
    const uint32_t xorVal = this->richSign->checksum;
    const size_t cnt = this->compIdCounter - 1;
    bool isOk = isOk;
    uint64_t num = this->getNumValue(fieldId, &isOk);
    if (!isOk) {
        return "";
    }
    switch (fieldId) {
        case DANS_ID:
        case CPAD0: case CPAD1: case CPAD2: {
            uint32_t my_num = static_cast<uint32_t>(num) ^ xorVal;
            return QString::number(my_num, 16);
        }
    }
    if (fieldId >= COMP_ID_1 && fieldId <= COMP_ID_1 + cnt)
    {
        uint64_t xorVal2 = xorVal | ((uint64_t)xorVal << sizeof(uint32_t)*8);
        uint64_t my_num = static_cast<uint64_t>(num) ^ (xorVal2);
        RICH_COMP_ID* myCompId = reinterpret_cast<RICH_COMP_ID*>(&my_num);
        return QString::number(myCompId->CV, 10) + "." + QString::number(myCompId->prodId, 10) + "." + QString::number(myCompId->count, 10);
    }
    return "";
}
<commit_msg>[FEATURE] In RichHdr: added "DanS" and "Rich" keywords in description<commit_after>#include "RichHdrWrapper.h"
#include "PEFile.h"
#include <iostream>

bool RichHdrWrapper::wrap()
{
    this->richSign = m_PE->getRichHeaderSign();
    this->dansHdr = m_PE->getRichHeaderBgn(richSign);
    this->compIdCounter = this->compIdCount();
    return true;
}

void* RichHdrWrapper::getPtr()
{
    RICH_SIGNATURE* richSign = m_PE->getRichHeaderSign();
    if (!richSign) {
        return nullptr;
    }
    RICH_DANS_HEADER* dansHdr = m_PE->getRichHeaderBgn(richSign);
    if (!dansHdr) {
        return nullptr;
    }
    return (void*)dansHdr;
}

size_t RichHdrWrapper::compIdCount()
{
    if (!this->richSign || !this->dansHdr) {
        return 0;
    }
    const RICH_DANS_HEADER dans_empty = { 0 };
    const bufsize_t dif = ((ULONGLONG)richSign - (ULONGLONG)dansHdr) - (sizeof(dans_empty.dansId) + sizeof(dans_empty.cPad));
    bufsize_t count = dif / sizeof(RICH_COMP_ID);
    return (size_t) count;
}

bufsize_t RichHdrWrapper::getSize()
{
    if (!this->richSign || !this->dansHdr) {
        return 0;
    }
    const size_t cnt = this->compIdCounter - 1;
    const bufsize_t dif = sizeof(RICH_DANS_HEADER) + sizeof(RICH_SIGNATURE) + (sizeof(RICH_COMP_ID) * cnt);
    return dif;
}

size_t RichHdrWrapper::getFieldsCount()
{
    if (getSize() == 0) return 0;
    return this->compIdCounter + FIELD_COUNTER - 1;
}

void* RichHdrWrapper::getFieldPtr(size_t fieldId, size_t subField)
{
    if (!this->richSign || !this->dansHdr) {
        return 0;
    }

    const size_t cnt = this->compIdCounter - 1;
    switch (fieldId) {
         case DANS_ID: return (void*) &dansHdr->dansId;
         case CPAD0: return (void*) &dansHdr->cPad[0];
         case CPAD1: return (void*) &dansHdr->cPad[1];
         case CPAD2: return (void*) &dansHdr->cPad[2];
         //case COMP_ID_1: return (void*) &dansHdr->compId;
         //case RICH_ID: return (void*) &richSign->richId;
         //case CHECKSUM: return (void*) &richSign->checksum;
    }
    if (fieldId >= COMP_ID_1 && fieldId <= COMP_ID_1 + cnt)
    {
        size_t compIdNum = fieldId - COMP_ID_1;
        return (void*)(ULONGLONG(&dansHdr->compId) + (sizeof(RICH_COMP_ID)*compIdNum));
    }
    if (fieldId == RICH_ID + cnt) return (void*) &richSign->richId;
    if (fieldId == CHECKSUM + cnt) return (void*) &richSign->checksum;
    return (void*) dansHdr;
}

QString RichHdrWrapper::getFieldName(size_t fieldId)
{
    if (!this->richSign || !this->dansHdr) {
        return "";
    }
    const size_t cnt = this->compIdCounter - 1;

    switch (fieldId) {
         case DANS_ID: return("DanS ID");
         case CPAD0: case CPAD1: case CPAD2:  return ("Checksumed padding");
    }
    if (fieldId >= COMP_ID_1 && fieldId <= COMP_ID_1 + cnt)
    {
        return("Comp ID");
    }
    if (fieldId == RICH_ID + cnt) return("Rich ID");
    if (fieldId == CHECKSUM + cnt) return("Checksum");
    return "";
}

Executable::addr_type RichHdrWrapper::containsAddrType(uint32_t fieldId, uint32_t subField)
{
    return Executable::NOT_ADDR;
}

QString RichHdrWrapper::translateFieldContent(size_t fieldId)
{
    if (!this->richSign || !this->dansHdr) {
        return "";
    }
    const uint32_t xorVal = this->richSign->checksum;
    const size_t cnt = this->compIdCounter - 1;

    bool isOk = isOk;
    uint64_t num = this->getNumValue(fieldId, &isOk);
    if (!isOk) {
        return "?";
    }
    switch (fieldId) {
        case DANS_ID:
        case CPAD0: case CPAD1: case CPAD2: {
            uint32_t my_num = static_cast<uint32_t>(num) ^ xorVal;
            if (my_num == DANS_HDR_MAGIC) return "DanS";
            return QString::number(my_num, 16);
        }
    }
    if (fieldId >= COMP_ID_1 && fieldId <= COMP_ID_1 + cnt)
    {
        uint64_t xorVal2 = xorVal | ((uint64_t)xorVal << sizeof(uint32_t)*8);
        uint64_t my_num = static_cast<uint64_t>(num) ^ (xorVal2);
        RICH_COMP_ID* myCompId = reinterpret_cast<RICH_COMP_ID*>(&my_num);
        return QString::number(myCompId->CV, 10) + "." + QString::number(myCompId->prodId, 10) + "." + QString::number(myCompId->count, 10);
    }
    if (fieldId == RICH_ID + cnt) {
        if (static_cast<uint32_t>(num) == RICH_HDR_MAGIC) return "Rich";
    }
    return "";
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Base class for the calibration components using
//  as input TPCseeds and ESDs
//  Event loop outside of the component
//
//
// Base functionality to be implemeneted by component
/*
   //In some cases only one of this function to be implemented
   virtual void     Process(AliESDEvent *event)
   virtual void     Process(AliTPCseed *track)
   //
   virtual Long64_t Merge(TCollection *li);
   virtual void     Analyze()
   void             Terminate();
*/
// Functionality provided by base class for Algorith debuging:
//  TTreeSRedirector * cstream =  GetDebugStreamer() - get debug streamer which can be use for numerical debugging
//

//  marian.ivanov@cern.ch
//
#include "AliTPCcalibBase.h"
#include "TSystem.h"
#include "TFile.h"
#include "TTreeStream.h"
#include "TTimeStamp.h"
#include "TGraph.h"
#include "TGraphErrors.h"
#include "TF1.h"
#include "TH1.h"
#include "THnSparse.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TAxis.h"

#include "AliLog.h"
#include "AliESDEvent.h"

ClassImp(AliTPCcalibBase)

AliTPCcalibBase::AliTPCcalibBase():
    TNamed(),
    fDebugStreamer(0),
    fStreamLevel(0),
    fRun(0),                  //!  current Run number
    fEvent(0),                //!  current Event number
    fTime(0),                 //!  current Time
    fTrigger(0),              //! current trigger type
    fMagF(0),                 //! current magnetic field
    fTriggerMaskReject(-1),   //trigger mask - reject trigger
    fTriggerMaskAccept(-1),   //trigger mask - accept trigger
    fHasLaser(kFALSE),                    //flag the laser is overlayed with given event
    fRejectLaser(kTRUE),                 //flag- reject laser
    fTriggerClass(),
    fCurrentEvent(0),           //! current event
    fCurrentTrack(0),           //! current esd track
    fCurrentFriendTrack(0),           //! current esd track
    fCurrentSeed(0),            //! current seed
    fDebugLevel(0)
{
  //
  // Constructor
  //
}

AliTPCcalibBase::AliTPCcalibBase(const char * name, const char * title):
  TNamed(name,title),
  fDebugStreamer(0),
  fStreamLevel(0),
  fRun(0),                  //!  current Run number
  fEvent(0),                //!  current Event number
  fTime(0),                 //!  current Time
  fTrigger(0),              //! current trigger type
  fMagF(0),                 //! current magnetic field
  fTriggerMaskReject(-1),   //trigger mask - reject trigger
  fTriggerMaskAccept(-1),   //trigger mask - accept trigger
  fHasLaser(kFALSE),                    //flag the laser is overlayed with given event
  fRejectLaser(kTRUE),                 //flag- reject laser
  fTriggerClass(),
  fCurrentEvent(0),           //! current event
  fCurrentTrack(0),           //! current esd track
  fCurrentFriendTrack(0),           //! current esd track
  fCurrentSeed(0),            //! current seed
  fDebugLevel(0)
{
  //
  // Constructor
  //
}

AliTPCcalibBase::AliTPCcalibBase(const AliTPCcalibBase&calib):
  TNamed(calib),
  fDebugStreamer(0),
  fStreamLevel(calib.fStreamLevel),
  fRun(0),                  //!  current Run number
  fEvent(0),                //!  current Event number
  fTime(0),                 //!  current Time
  fTrigger(0),              //! current trigger type
  fMagF(0),                 //! current magnetic field
  fTriggerMaskReject(calib.fTriggerMaskReject),   //trigger mask - reject trigger
  fTriggerMaskAccept(calib.fTriggerMaskAccept),   //trigger mask - accept trigger
  fHasLaser(calib.fHasLaser),                    //flag the laser is overlayed with given event
  fRejectLaser(calib.fRejectLaser),                 //flag- reject laser
  fTriggerClass(calib.fTriggerClass),
  fCurrentEvent(0),           //! current event
  fCurrentTrack(0),           //! current esd track
  fCurrentFriendTrack(0),           //! current esd track
  fCurrentSeed(0),            //! current seed
  fDebugLevel(calib.fDebugLevel)
{
  //
  // copy constructor
  //
}

AliTPCcalibBase &AliTPCcalibBase::operator=(const AliTPCcalibBase&calib){
  //
  // operator=
  //
  ((TNamed *)this)->operator=(calib);
  fDebugStreamer=0;
  fStreamLevel=calib.fStreamLevel;
  fDebugLevel=calib.fDebugLevel;
  return *this;
}

AliTPCcalibBase::~AliTPCcalibBase() {
  //
  // destructor
  //
  if (fDebugLevel>0) printf("AliTPCcalibBase::~AliTPCcalibBase\n");
  if (fDebugStreamer) delete fDebugStreamer;
  fDebugStreamer=0;
}

void  AliTPCcalibBase::Terminate(){
  //
  //
  //
  if (fDebugLevel>0) printf("AliTPCcalibBase::Terminate\n");
  if (fDebugStreamer) delete fDebugStreamer;
  fDebugStreamer = 0;
  return;
}

TTreeSRedirector *AliTPCcalibBase::GetDebugStreamer(){
  //
  // Get Debug streamer
  // In case debug streamer not yet initialized and StreamLevel>0 create new one
  //
  if (fStreamLevel==0) return 0;
  if (fDebugStreamer) return fDebugStreamer;
  TString dsName;
  dsName=GetName();
  dsName+="Debug.root";
  dsName.ReplaceAll(" ","");
  fDebugStreamer = new TTreeSRedirector(dsName.Data());
  return fDebugStreamer;
}

void    AliTPCcalibBase::UpdateEventInfo(AliESDEvent * event){
  //
  //
  //
  fRun     = event->GetRunNumber();
  fEvent   = event->GetEventNumberInFile();
  fTime    = event->GetTimeStamp();
  fTrigger = event->GetTriggerMask();
  fMagF    = event->GetMagneticField();
  fTriggerClass = event->GetFiredTriggerClasses().Data();
  fHasLaser = HasLaser(event);

}

Bool_t AliTPCcalibBase::HasLaser(AliESDEvent *event){
  //
  //
  //
  // Thresholds more than 8 tracks with small dip angle

  const Int_t kMinLaserTracks = 8;
  const Float_t kThrLaser       = 0.3;
  const Float_t kLaserTgl       = 0.01;

  Int_t ntracks = event->GetNumberOfTracks();
  if (ntracks<kMinLaserTracks) return kFALSE;
  Float_t nlaser=0;
  Float_t nall=0;
  for (Int_t i=0;i<ntracks;++i) {
    AliESDtrack *track=event->GetTrack(i);
    if (!track) continue;
    if (track->GetTPCNcls()<=0) continue;
    nall++;
    if (TMath::Abs(track->GetTgl())<kLaserTgl) nlaser++;
  }
  if (nlaser>kMinLaserTracks) return kTRUE;
  if (nall>0 && nlaser/nall>kThrLaser) return kTRUE;
  return kFALSE;
}

Bool_t AliTPCcalibBase::AcceptTrigger(){
  //
  // Apply trigger mask - Don't do calibration for non proper triggers
  //
  if (fTriggerMaskReject==(Int_t)fTrigger) return kFALSE;
  if (fTriggerMaskAccept>0 && fTriggerMaskAccept!=(Int_t)fTrigger) return kFALSE;
  if (fHasLaser && fRejectLaser) return kFALSE;
  return kTRUE;
}

void AliTPCcalibBase::RegisterDebugOutput(const char *path){
  //
  // store  - copy debug output to the destination position
  // currently ONLY for local copy
  if (fDebugLevel>0) printf("AliTPCcalibBase::RegisterDebugOutput(%s)\n",path);
  if (fStreamLevel==0) return;
  TString dsName;
  dsName=GetName();
  dsName+="Debug.root";
  dsName.ReplaceAll(" ","");
  TString dsName2=path;
  gSystem->MakeDirectory(dsName2.Data());
  dsName2+=gSystem->HostName();
  gSystem->MakeDirectory(dsName2.Data());
  dsName2+="/";
  TTimeStamp s;
  dsName2+=Int_t(s.GetNanoSec());
  dsName2+="/";
  gSystem->MakeDirectory(dsName2.Data());
  dsName2+=dsName;
  AliInfo(Form("copy %s\t%s\n",dsName.Data(),dsName2.Data()));
  printf("copy %s\t%s\n",dsName.Data(),dsName2.Data());
  TFile::Cp(dsName.Data(),dsName2.Data());
}

TGraphErrors * AliTPCcalibBase::FitSlices(THnSparse *h, Int_t axisDim1, Int_t axisDim2, Int_t minEntries, Int_t nmaxBin, Float_t fracLow, Float_t fracUp, Bool_t useMedian, TTreeSRedirector *cstream, Int_t ival){
  //
  // Fitting slices of the projection(axisDim1,axisDim2) of a sparse histogram
  //
  TF1 funcGaus("funcGaus","gaus");
  TH2D * hist = h->Projection(axisDim1, axisDim2);
  Double_t *xvec = new Double_t[hist->GetNbinsX()];
  Double_t *yvec = new Double_t[hist->GetNbinsX()];
  Double_t *xerr = new Double_t[hist->GetNbinsX()];
  Double_t *yerr = new Double_t[hist->GetNbinsX()];
  Int_t counter  = 0;
  TH1D * projectionHist =0;
  //

  for(Int_t i=1; i <= hist->GetNbinsX(); i++) {
    Int_t nsum=0;
    Int_t imin   =  i;
    Int_t imax   =  i;

    for (Int_t idelta=0; idelta<nmaxBin; idelta++){
      //
      imin   =  TMath::Max(i-idelta,1);
      imax   =  TMath::Min(i+idelta,hist->GetNbinsX());
      nsum = TMath::Nint(hist->Integral(imin,imax,0,hist->GetNbinsY()));
      if (nsum==0) break;
      if (nsum>minEntries) break;
    }
    if (nsum<minEntries) continue;
    //
    hist->GetXaxis()->SetRange(imin,imax);
    projectionHist = hist->ProjectionY("gain",imin,imax);
    // Determine Median:
    Float_t xMin = projectionHist->GetXaxis()->GetXmin();
    Float_t xMax = projectionHist->GetXaxis()->GetXmax();
    Float_t xMedian = (xMin+xMax)*0.5;
    Float_t integral = 0;
    for(Int_t jbin=1; jbin<projectionHist->GetNbinsX()-1; jbin++) {
      integral+=projectionHist->GetBinContent(jbin);
    }
    //printf("Integral %f\t%f\n",integral, projectionHist->GetSum());
    //
    //
    Float_t currentSum=0;
    for(Int_t jbin=1; jbin<projectionHist->GetNbinsX()-1; jbin++) {
      currentSum += projectionHist->GetBinContent(jbin);
      if (currentSum<fracLow*integral) xMin = projectionHist->GetBinCenter(jbin);
      if (currentSum<fracUp*integral)  xMax = projectionHist->GetBinCenter(jbin+1);
      if (currentSum<0.5*integral && projectionHist->GetBinContent(jbin)>0){
	xMedian = (projectionHist->GetBinCenter(jbin)*projectionHist->GetBinContent(jbin)+
		   projectionHist->GetBinCenter(jbin+1)*projectionHist->GetBinContent(jbin+1))/
	  (projectionHist->GetBinContent(jbin)+projectionHist->GetBinContent(jbin+1));
      }
    }
    //
    Float_t rms  = projectionHist->GetRMS();
    //    i += interval;
    //
    Double_t xcenter =  hist->GetMean();
    Double_t xrms    =  hist->GetRMS()+hist->GetXaxis()->GetBinWidth(1)/TMath::Sqrt(12.);
    Double_t binWidth = projectionHist->GetXaxis()->GetBinWidth(1);
    if (rms>0){
      // cut on +- 4 RMS
      projectionHist->Fit(&funcGaus,"QN","",xMin, xMax);
      Double_t chi2 = funcGaus.GetChisquare();
      //
      xvec[counter] = xcenter;
      yvec[counter] = funcGaus.GetParameter(ival);
      xerr[counter] = xrms;
      yerr[counter] = funcGaus.GetParError(ival);
      if (useMedian) yvec[counter] = xMedian;
      if (cstream){
	(*cstream)<<"fitDebug"<<
	  "xcenter="<<xcenter<<
	  "xMin="<<xMin<<
	  "xMax="<<xMax<<
	  "xMedian="<<xMedian<<
	  "xFitM"<<yvec[counter]<<
	  "xFitS"<<yerr[counter]<<
	  "chi2="<<chi2<<
	  "\n";
      }
      counter++;
    }else{
      xvec[counter] = xcenter;
      yvec[counter] = xMedian;
      xerr[counter] = xrms;
      yerr[counter] = binWidth/TMath::Sqrt(12.);
      counter++;
    }
    delete projectionHist;
  }

  TGraphErrors * graphErrors = new TGraphErrors(counter, xvec, yvec, xerr, yerr);
  delete [] xvec;
  delete [] yvec;
  delete [] xerr;
  delete [] yerr;
  delete hist;
  return graphErrors;
}

void AliTPCcalibBase::BinLogX(THnSparse *h, Int_t axisDim) {

  // Method for the correct logarithmic binning of histograms

  TAxis *axis = h->GetAxis(axisDim);
  int bins = axis->GetNbins();

  Double_t from = axis->GetXmin();
  Double_t to = axis->GetXmax();
  Double_t *new_bins = new Double_t[bins + 1];

  new_bins[0] = from;
  Double_t factor = pow(to/from, 1./bins);

  for (int i = 1; i <= bins; i++) {
   new_bins[i] = factor * new_bins[i-1];
  }
  axis->Set(bins, new_bins);
  delete [] new_bins;

}
void AliTPCcalibBase::BinLogX(TH1 *h) {

  // Method for the correct logarithmic binning of histograms

  TAxis *axis = h->GetXaxis();
  int bins = axis->GetNbins();

  Double_t from = axis->GetXmin();
  Double_t to = axis->GetXmax();
  Double_t *new_bins = new Double_t[bins + 1];

  new_bins[0] = from;
  Double_t factor = pow(to/from, 1./bins);

  for (int i = 1; i <= bins; i++) {
   new_bins[i] = factor * new_bins[i-1];
  }
  axis->Set(bins, new_bins);
  delete [] new_bins;

}
<commit_msg>Use event specie to identufy laser events (Marian)<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Base class for the calibration components using
//  as input TPCseeds and ESDs
//  Event loop outside of the component
//
//
// Base functionality to be implemeneted by component
/*
   //In some cases only one of this function to be implemented
   virtual void     Process(AliESDEvent *event)
   virtual void     Process(AliTPCseed *track)
   //
   virtual Long64_t Merge(TCollection *li);
   virtual void     Analyze()
   void             Terminate();
*/
// Functionality provided by base class for Algorith debuging:
//  TTreeSRedirector * cstream =  GetDebugStreamer() - get debug streamer which can be use for numerical debugging
//

//  marian.ivanov@cern.ch
//
#include "AliTPCcalibBase.h"
#include "TSystem.h"
#include "TFile.h"
#include "TTreeStream.h"
#include "TTimeStamp.h"
#include "TGraph.h"
#include "TGraphErrors.h"
#include "TF1.h"
#include "TH1.h"
#include "THnSparse.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TAxis.h"
#include "AliRecoParam.h"

#include "AliLog.h"
#include "AliESDEvent.h"

ClassImp(AliTPCcalibBase)

AliTPCcalibBase::AliTPCcalibBase():
    TNamed(),
    fDebugStreamer(0),
    fStreamLevel(0),
    fRun(0),                  //!  current Run number
    fEvent(0),                //!  current Event number
    fTime(0),                 //!  current Time
    fTrigger(0),              //! current trigger type
    fMagF(0),                 //! current magnetic field
    fTriggerMaskReject(-1),   //trigger mask - reject trigger
    fTriggerMaskAccept(-1),   //trigger mask - accept trigger
    fHasLaser(kFALSE),                    //flag the laser is overlayed with given event
    fRejectLaser(kTRUE),                 //flag- reject laser
    fTriggerClass(),
    fCurrentEvent(0),           //! current event
    fCurrentTrack(0),           //! current esd track
    fCurrentFriendTrack(0),           //! current esd track
    fCurrentSeed(0),            //! current seed
    fDebugLevel(0)
{
  //
  // Constructor
  //
}

AliTPCcalibBase::AliTPCcalibBase(const char * name, const char * title):
  TNamed(name,title),
  fDebugStreamer(0),
  fStreamLevel(0),
  fRun(0),                  //!  current Run number
  fEvent(0),                //!  current Event number
  fTime(0),                 //!  current Time
  fTrigger(0),              //! current trigger type
  fMagF(0),                 //! current magnetic field
  fTriggerMaskReject(-1),   //trigger mask - reject trigger
  fTriggerMaskAccept(-1),   //trigger mask - accept trigger
  fHasLaser(kFALSE),                    //flag the laser is overlayed with given event
  fRejectLaser(kTRUE),                 //flag- reject laser
  fTriggerClass(),
  fCurrentEvent(0),           //! current event
  fCurrentTrack(0),           //! current esd track
  fCurrentFriendTrack(0),           //! current esd track
  fCurrentSeed(0),            //! current seed
  fDebugLevel(0)
{
  //
  // Constructor
  //
}

AliTPCcalibBase::AliTPCcalibBase(const AliTPCcalibBase&calib):
  TNamed(calib),
  fDebugStreamer(0),
  fStreamLevel(calib.fStreamLevel),
  fRun(0),                  //!  current Run number
  fEvent(0),                //!  current Event number
  fTime(0),                 //!  current Time
  fTrigger(0),              //! current trigger type
  fMagF(0),                 //! current magnetic field
  fTriggerMaskReject(calib.fTriggerMaskReject),   //trigger mask - reject trigger
  fTriggerMaskAccept(calib.fTriggerMaskAccept),   //trigger mask - accept trigger
  fHasLaser(calib.fHasLaser),                    //flag the laser is overlayed with given event
  fRejectLaser(calib.fRejectLaser),                 //flag- reject laser
  fTriggerClass(calib.fTriggerClass),
  fCurrentEvent(0),           //! current event
  fCurrentTrack(0),           //! current esd track
  fCurrentFriendTrack(0),           //! current esd track
  fCurrentSeed(0),            //! current seed
  fDebugLevel(calib.fDebugLevel)
{
  //
  // copy constructor
  //
}

AliTPCcalibBase &AliTPCcalibBase::operator=(const AliTPCcalibBase&calib){
  //
  // operator=
  //
  ((TNamed *)this)->operator=(calib);
  fDebugStreamer=0;
  fStreamLevel=calib.fStreamLevel;
  fDebugLevel=calib.fDebugLevel;
  return *this;
}

AliTPCcalibBase::~AliTPCcalibBase() {
  //
  // destructor
  //
  if (fDebugLevel>0) printf("AliTPCcalibBase::~AliTPCcalibBase\n");
  if (fDebugStreamer) delete fDebugStreamer;
  fDebugStreamer=0;
}

void  AliTPCcalibBase::Terminate(){
  //
  //
  //
  if (fDebugLevel>0) printf("AliTPCcalibBase::Terminate\n");
  if (fDebugStreamer) delete fDebugStreamer;
  fDebugStreamer = 0;
  return;
}

TTreeSRedirector *AliTPCcalibBase::GetDebugStreamer(){
  //
  // Get Debug streamer
  // In case debug streamer not yet initialized and StreamLevel>0 create new one
  //
  if (fStreamLevel==0) return 0;
  if (fDebugStreamer) return fDebugStreamer;
  TString dsName;
  dsName=GetName();
  dsName+="Debug.root";
  dsName.ReplaceAll(" ","");
  fDebugStreamer = new TTreeSRedirector(dsName.Data());
  return fDebugStreamer;
}

void    AliTPCcalibBase::UpdateEventInfo(AliESDEvent * event){
  //
  //
  //
  fRun     = event->GetRunNumber();
  fEvent   = event->GetEventNumberInFile();
  fTime    = event->GetTimeStamp();
  fTrigger = event->GetTriggerMask();
  fMagF    = event->GetMagneticField();
  fTriggerClass = event->GetFiredTriggerClasses().Data();
  fHasLaser = HasLaser(event);

}

Bool_t AliTPCcalibBase::HasLaser(AliESDEvent *event){
  //
  //
  //
  // Use event specie
  Bool_t isLaser=kFALSE;
  UInt_t specie = event->GetEventSpecie();  // select only cosmic events
  if (specie==AliRecoParam::kCalib) {
    isLaser = kTRUE;
  }
  return isLaser;
}

Bool_t AliTPCcalibBase::AcceptTrigger(){
  //
  // Apply trigger mask - Don't do calibration for non proper triggers
  //
  if (fTriggerMaskReject==(Int_t)fTrigger) return kFALSE;
  if (fTriggerMaskAccept>0 && fTriggerMaskAccept!=(Int_t)fTrigger) return kFALSE;
  if (fHasLaser && fRejectLaser) return kFALSE;
  return kTRUE;
}

void AliTPCcalibBase::RegisterDebugOutput(const char *path){
  //
  // store  - copy debug output to the destination position
  // currently ONLY for local copy
  if (fDebugLevel>0) printf("AliTPCcalibBase::RegisterDebugOutput(%s)\n",path);
  if (fStreamLevel==0) return;
  TString dsName;
  dsName=GetName();
  dsName+="Debug.root";
  dsName.ReplaceAll(" ","");
  TString dsName2=path;
  gSystem->MakeDirectory(dsName2.Data());
  dsName2+=gSystem->HostName();
  gSystem->MakeDirectory(dsName2.Data());
  dsName2+="/";
  TTimeStamp s;
  dsName2+=Int_t(s.GetNanoSec());
  dsName2+="/";
  gSystem->MakeDirectory(dsName2.Data());
  dsName2+=dsName;
  AliInfo(Form("copy %s\t%s\n",dsName.Data(),dsName2.Data()));
  printf("copy %s\t%s\n",dsName.Data(),dsName2.Data());
  TFile::Cp(dsName.Data(),dsName2.Data());
}

TGraphErrors * AliTPCcalibBase::FitSlices(THnSparse *h, Int_t axisDim1, Int_t axisDim2, Int_t minEntries, Int_t nmaxBin, Float_t fracLow, Float_t fracUp, Bool_t useMedian, TTreeSRedirector *cstream, Int_t ival){
  //
  // Fitting slices of the projection(axisDim1,axisDim2) of a sparse histogram
  //
  TF1 funcGaus("funcGaus","gaus");
  TH2D * hist = h->Projection(axisDim1, axisDim2);
  Double_t *xvec = new Double_t[hist->GetNbinsX()];
  Double_t *yvec = new Double_t[hist->GetNbinsX()];
  Double_t *xerr = new Double_t[hist->GetNbinsX()];
  Double_t *yerr = new Double_t[hist->GetNbinsX()];
  Int_t counter  = 0;
  TH1D * projectionHist =0;
  //

  for(Int_t i=1; i <= hist->GetNbinsX(); i++) {
    Int_t nsum=0;
    Int_t imin   =  i;
    Int_t imax   =  i;

    for (Int_t idelta=0; idelta<nmaxBin; idelta++){
      //
      imin   =  TMath::Max(i-idelta,1);
      imax   =  TMath::Min(i+idelta,hist->GetNbinsX());
      nsum = TMath::Nint(hist->Integral(imin,imax,0,hist->GetNbinsY()));
      if (nsum==0) break;
      if (nsum>minEntries) break;
    }
    if (nsum<minEntries) continue;
    //
    hist->GetXaxis()->SetRange(imin,imax);
    projectionHist = hist->ProjectionY("gain",imin,imax);
    // Determine Median:
    Float_t xMin = projectionHist->GetXaxis()->GetXmin();
    Float_t xMax = projectionHist->GetXaxis()->GetXmax();
    Float_t xMedian = (xMin+xMax)*0.5;
    Float_t integral = 0;
    for(Int_t jbin=1; jbin<projectionHist->GetNbinsX()-1; jbin++) {
      integral+=projectionHist->GetBinContent(jbin);
    }
    //printf("Integral %f\t%f\n",integral, projectionHist->GetSum());
    //
    //
    Float_t currentSum=0;
    for(Int_t jbin=1; jbin<projectionHist->GetNbinsX()-1; jbin++) {
      currentSum += projectionHist->GetBinContent(jbin);
      if (currentSum<fracLow*integral) xMin = projectionHist->GetBinCenter(jbin);
      if (currentSum<fracUp*integral)  xMax = projectionHist->GetBinCenter(jbin+1);
      if (currentSum<0.5*integral && projectionHist->GetBinContent(jbin)>0){
	xMedian = (projectionHist->GetBinCenter(jbin)*projectionHist->GetBinContent(jbin)+
		   projectionHist->GetBinCenter(jbin+1)*projectionHist->GetBinContent(jbin+1))/
	  (projectionHist->GetBinContent(jbin)+projectionHist->GetBinContent(jbin+1));
      }
    }
    //
    Float_t rms  = projectionHist->GetRMS();
    //    i += interval;
    //
    Double_t xcenter =  hist->GetMean();
    Double_t xrms    =  hist->GetRMS()+hist->GetXaxis()->GetBinWidth(1)/TMath::Sqrt(12.);
    Double_t binWidth = projectionHist->GetXaxis()->GetBinWidth(1);
    if (rms>0){
      // cut on +- 4 RMS
      projectionHist->Fit(&funcGaus,"QN","",xMin, xMax);
      Double_t chi2 = funcGaus.GetChisquare();
      //
      xvec[counter] = xcenter;
      yvec[counter] = funcGaus.GetParameter(ival);
      xerr[counter] = xrms;
      yerr[counter] = funcGaus.GetParError(ival);
      if (useMedian) yvec[counter] = xMedian;
      if (cstream){
	(*cstream)<<"fitDebug"<<
	  "xcenter="<<xcenter<<
	  "xMin="<<xMin<<
	  "xMax="<<xMax<<
	  "xMedian="<<xMedian<<
	  "xFitM"<<yvec[counter]<<
	  "xFitS"<<yerr[counter]<<
	  "chi2="<<chi2<<
	  "\n";
      }
      counter++;
    }else{
      xvec[counter] = xcenter;
      yvec[counter] = xMedian;
      xerr[counter] = xrms;
      yerr[counter] = binWidth/TMath::Sqrt(12.);
      counter++;
    }
    delete projectionHist;
  }

  TGraphErrors * graphErrors = new TGraphErrors(counter, xvec, yvec, xerr, yerr);
  delete [] xvec;
  delete [] yvec;
  delete [] xerr;
  delete [] yerr;
  delete hist;
  return graphErrors;
}

void AliTPCcalibBase::BinLogX(THnSparse *h, Int_t axisDim) {

  // Method for the correct logarithmic binning of histograms

  TAxis *axis = h->GetAxis(axisDim);
  int bins = axis->GetNbins();

  Double_t from = axis->GetXmin();
  Double_t to = axis->GetXmax();
  Double_t *new_bins = new Double_t[bins + 1];

  new_bins[0] = from;
  Double_t factor = pow(to/from, 1./bins);

  for (int i = 1; i <= bins; i++) {
   new_bins[i] = factor * new_bins[i-1];
  }
  axis->Set(bins, new_bins);
  delete [] new_bins;

}
void AliTPCcalibBase::BinLogX(TH1 *h) {

  // Method for the correct logarithmic binning of histograms

  TAxis *axis = h->GetXaxis();
  int bins = axis->GetNbins();

  Double_t from = axis->GetXmin();
  Double_t to = axis->GetXmax();
  Double_t *new_bins = new Double_t[bins + 1];

  new_bins[0] = from;
  Double_t factor = pow(to/from, 1./bins);

  for (int i = 1; i <= bins; i++) {
   new_bins[i] = factor * new_bins[i-1];
  }
  axis->Set(bins, new_bins);
  delete [] new_bins;

}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Sony Corporation. 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 obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <nbla/computation_graph/computation_graph.hpp>

#include <algorithm>
#include <memory>

namespace nbla {

using std::make_shared;

static void set_function_inputs(CgFunctionPtr func,
                                const vector<CgVariablePtr> &inputs) {
  // Check need_grad
  bool need_grad = false;
  int rank = 0;
  for (auto i : inputs) {
    need_grad |= i->need_grad_state();
    rank = std::max(rank, i->rank());
    i->insert_function_reference(func);
  }
  func->set_need_grad(need_grad);
  func->set_rank_(rank);
  func->set_inputs_(inputs);
}

vector<CgVariablePtr> create_function_outputs(CgFunctionPtr cg_f, int n_outputs,
                                              bool prohibit_clear_output) {
  // Check inplace outputs size and create outputs.
  if (n_outputs < 0) {
    n_outputs = cg_f->function()->min_outputs();
  }
  vector<CgVariablePtr> outputs(n_outputs);
  for (int i = 0; i < n_outputs; ++i) {
    auto v = make_shared<CgVariable>();
    v->set_need_grad_state(cg_f->need_grad());
    v->set_parent(cg_f);
    v->set_prohibit_clear_data(prohibit_clear_output);
    outputs[i] = v;
  }
  // Weak references are held inside.
  cg_f->set_outputs(outputs);
  // Return strong references.
  return outputs;
}

vector<CgVariablePtr> connect(CgFunctionPtr cg_f,
                              const vector<CgVariablePtr> &inputs,
                              int n_outputs, vector<NdArrayPtr> inplace_outputs,
                              bool execute) {
  set_function_inputs(cg_f, inputs);

  // check if data can be cleared or not.
  bool persistent = false, inplace = false, prohibit_clear = false;
  for (int i = 0; i < inputs.size(); ++i) {
    auto inp = inputs[i];
    persistent |= inp->rank() == 0 || inp->persistent();
    prohibit_clear |= inp->prohibit_clear_data();
    inplace |= cg_f->function()->inplace_data(i) > 0;
  }

  bool prohibit_output_clear = (prohibit_clear || persistent) && inplace;

  vector<CgVariablePtr> outputs =
      create_function_outputs(cg_f, n_outputs, prohibit_output_clear);

  // Setup function.
  cg_f->setup();

  // Verify connections.
  cg_f->verify_during_forward();

  // Function inputs and outputs must be Variables.
  vector<Variable *> finputs(inputs.size());
  vector<Variable *> foutputs(outputs.size());
  for (int i = 0; i < inputs.size(); ++i) {
    finputs[i] = inputs[i]->variable().get();
  }
  for (int i = 0; i < outputs.size(); ++i) {
    foutputs[i] = outputs[i]->variable().get();
  }

  // Set array reference to function output buffer if size matches.
  for (int i = 0; i < outputs.size(); ++i) {
    if (i >= inplace_outputs.size() || !inplace_outputs[i])
      continue;
    NBLA_CHECK(inplace_outputs[i]->size() == foutputs[i]->size(),
               error_code::value,
               "In-place array size and function output size must match. "
               "inplace_outputs[%d]: %d != function_output[%d]: %d.",
               inplace_outputs[i]->size(), foutputs[i]->size());
    foutputs[i]->data()->set_array(inplace_outputs[i]->array());
  }

  if (execute) {
    // Execute Forward.
    cg_f->function()->forward(finputs, foutputs);
  }
  return outputs;
}

void steal_variable_from_to(CgVariablePtr from, CgVariablePtr to) {
  // A. The shape must the same
  NBLA_CHECK(
      to->variable()->shape() == from->variable()->shape(), error_code::value,
      "Variable shapes of from and to must match. from != to : (%s) != (%s).",
      string_join(from->variable()->shape(), ", ").c_str(),
      string_join(to->variable()->shape(), ", ").c_str());
  // B. Get a parent function of from
  auto parent = from->parent();
  NBLA_CHECK(parent != nullptr, error_code::value,
             "The 1st argument CgVariablePtr must have a parent function (must "
             "be an output of a function.");

  // C. Forget parent of from and rewire the parent function to to variable.
  from->set_parent(nullptr);
  to->set_parent(parent);

  // D. Replace an output variable reference of the parent function with to
  // variable.
  auto outputs = parent->outputs();
  std::replace(outputs.begin(), outputs.end(), from, to);
  parent->set_outputs(outputs);

  // E. Copy flags.
  to->set_allow_modify_data(from->allow_modify_data());
  if (from->need_grad_is_set()) {
    to->set_need_grad(from->need_grad());
  } else {
    to->unset_need_grad();
  }
  to->set_prohibit_clear_data(from->prohibit_clear_data());

  // F. Reference contents
  to->set_variable(from->variable());

  // G. Set setup flag.
  to->mark_need_setup();
}

void forward_all(const vector<CgVariablePtr> variables, bool clear_buffer,
                 bool clear_no_need_grad, function_hook_type function_pre_hook,
                 function_hook_type function_post_hook) {
  unordered_set<CgFunctionPtr> fclosed;
  for (int i = 0; i < variables.size(); ++i) {
    variables[i]->forward(clear_buffer, clear_no_need_grad, &fclosed,
                          function_pre_hook, function_post_hook);
  }
}
}
<commit_msg>[c++] Python-like API allows optional input by nullptr<commit_after>// Copyright (c) 2017 Sony Corporation. 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 obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <nbla/computation_graph/computation_graph.hpp>

#include <algorithm>
#include <memory>

namespace nbla {

using std::make_shared;

static void set_function_inputs(CgFunctionPtr func,
                                const vector<CgVariablePtr> &inputs) {
  // Check need_grad
  bool need_grad = false;
  int rank = 0;
  for (auto i : inputs) {
    need_grad |= i->need_grad_state();
    rank = std::max(rank, i->rank());
    i->insert_function_reference(func);
  }
  func->set_need_grad(need_grad);
  func->set_rank_(rank);
  func->set_inputs_(inputs);
}

vector<CgVariablePtr> create_function_outputs(CgFunctionPtr cg_f, int n_outputs,
                                              bool prohibit_clear_output) {
  // Check inplace outputs size and create outputs.
  if (n_outputs < 0) {
    n_outputs = cg_f->function()->min_outputs();
  }
  vector<CgVariablePtr> outputs(n_outputs);
  for (int i = 0; i < n_outputs; ++i) {
    auto v = make_shared<CgVariable>();
    v->set_need_grad_state(cg_f->need_grad());
    v->set_parent(cg_f);
    v->set_prohibit_clear_data(prohibit_clear_output);
    outputs[i] = v;
  }
  // Weak references are held inside.
  cg_f->set_outputs(outputs);
  // Return strong references.
  return outputs;
}

vector<CgVariablePtr> connect(CgFunctionPtr cg_f,
                              const vector<CgVariablePtr> &inputs_orig,
                              int n_outputs, vector<NdArrayPtr> inplace_outputs,
                              bool execute) {
  // Filter null inputs (since cpp functions doesn't handle optional inputs in
  // functions.cpp)
  vector<CgVariablePtr> inputs;
  for (auto &inp : inputs_orig) {
    if (inp) {
      inputs.push_back(inp);
    }
  }

  set_function_inputs(cg_f, inputs);

  // check if data can be cleared or not.
  bool persistent = false, inplace = false, prohibit_clear = false;
  for (int i = 0; i < inputs.size(); ++i) {
    auto inp = inputs[i];
    persistent |= inp->rank() == 0 || inp->persistent();
    prohibit_clear |= inp->prohibit_clear_data();
    inplace |= cg_f->function()->inplace_data(i) > 0;
  }

  bool prohibit_output_clear = (prohibit_clear || persistent) && inplace;

  vector<CgVariablePtr> outputs =
      create_function_outputs(cg_f, n_outputs, prohibit_output_clear);

  // Setup function.
  cg_f->setup();

  // Verify connections.
  cg_f->verify_during_forward();

  // Function inputs and outputs must be Variables.
  vector<Variable *> finputs(inputs.size());
  vector<Variable *> foutputs(outputs.size());
  for (int i = 0; i < inputs.size(); ++i) {
    finputs[i] = inputs[i]->variable().get();
  }
  for (int i = 0; i < outputs.size(); ++i) {
    foutputs[i] = outputs[i]->variable().get();
  }

  // Set array reference to function output buffer if size matches.
  for (int i = 0; i < outputs.size(); ++i) {
    if (i >= inplace_outputs.size() || !inplace_outputs[i])
      continue;
    NBLA_CHECK(inplace_outputs[i]->size() == foutputs[i]->size(),
               error_code::value,
               "In-place array size and function output size must match. "
               "inplace_outputs[%d]: %d != function_output[%d]: %d.",
               inplace_outputs[i]->size(), foutputs[i]->size());
    foutputs[i]->data()->set_array(inplace_outputs[i]->array());
  }

  if (execute) {
    // Execute Forward.
    cg_f->function()->forward(finputs, foutputs);
  }
  return outputs;
}

void steal_variable_from_to(CgVariablePtr from, CgVariablePtr to) {
  // A. The shape must the same
  NBLA_CHECK(
      to->variable()->shape() == from->variable()->shape(), error_code::value,
      "Variable shapes of from and to must match. from != to : (%s) != (%s).",
      string_join(from->variable()->shape(), ", ").c_str(),
      string_join(to->variable()->shape(), ", ").c_str());
  // B. Get a parent function of from
  auto parent = from->parent();
  NBLA_CHECK(parent != nullptr, error_code::value,
             "The 1st argument CgVariablePtr must have a parent function (must "
             "be an output of a function.");

  // C. Forget parent of from and rewire the parent function to to variable.
  from->set_parent(nullptr);
  to->set_parent(parent);

  // D. Replace an output variable reference of the parent function with to
  // variable.
  auto outputs = parent->outputs();
  std::replace(outputs.begin(), outputs.end(), from, to);
  parent->set_outputs(outputs);

  // E. Copy flags.
  to->set_allow_modify_data(from->allow_modify_data());
  if (from->need_grad_is_set()) {
    to->set_need_grad(from->need_grad());
  } else {
    to->unset_need_grad();
  }
  to->set_prohibit_clear_data(from->prohibit_clear_data());

  // F. Reference contents
  to->set_variable(from->variable());

  // G. Set setup flag.
  to->mark_need_setup();
}

void forward_all(const vector<CgVariablePtr> variables, bool clear_buffer,
                 bool clear_no_need_grad, function_hook_type function_pre_hook,
                 function_hook_type function_post_hook) {
  unordered_set<CgFunctionPtr> fclosed;
  for (int i = 0; i < variables.size(); ++i) {
    variables[i]->forward(clear_buffer, clear_no_need_grad, &fclosed,
                          function_pre_hook, function_post_hook);
  }
}
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo 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 obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "cyber/transport/shm/condition_notifier.h"

#include <sys/ipc.h>
#include <sys/shm.h>
#include <thread>

#include "cyber/common/log.h"
#include "cyber/common/util.h"

namespace apollo {
namespace cyber {
namespace transport {

using common::Hash;

ConditionNotifier::ConditionNotifier() {
  key_ = static_cast<key_t>(Hash("/apollo/cyber/transport/shm/notifier"));
  ADEBUG << "condition notifier key: " << key_;
  shm_size_ = sizeof(Indicator);

  if (!Init()) {
    AERROR << "fail to init condition notifier.";
    is_shutdown_.store(true);
    return;
  }
  next_seq_ = indicator_->next_seq.load();
  ADEBUG << "next_seq: " << next_seq_;
}

ConditionNotifier::~ConditionNotifier() { Shutdown(); }

void ConditionNotifier::Shutdown() {
  if (is_shutdown_.exchange(true)) {
    return;
  }

  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  Reset();
}

bool ConditionNotifier::Notify(const ReadableInfo& info) {
  if (is_shutdown_.load()) {
    ADEBUG << "notifier is shutdown.";
    return false;
  }

  uint64_t seq = indicator_->next_seq.fetch_add(1);
  uint64_t idx = seq % kBufLength;
  indicator_->infos[idx] = info;
  indicator_->seqs[idx] = seq;

  return true;
}

bool ConditionNotifier::Listen(int timeout_ms, ReadableInfo* info) {
  if (info == nullptr) {
    AERROR << "info nullptr.";
    return false;
  }

  if (is_shutdown_.load()) {
    ADEBUG << "notifier is shutdown.";
    return false;
  }

  int timeout_us = timeout_ms * 1000;
  while (!is_shutdown_.load()) {
    uint64_t seq = indicator_->next_seq.load();
    if (seq != next_seq_) {
      auto idx = next_seq_ % kBufLength;
      if (indicator_->seqs[idx] == next_seq_) {
        *info = indicator_->infos[idx];
        ++next_seq_;
        return true;
      } else {
        ADEBUG << "seq[" << next_seq_ << "] is writing, can not read now.";
      }
    }

    if (timeout_us > 0) {
      std::this_thread::sleep_for(std::chrono::microseconds(50));
      timeout_us -= 50;
    } else {
      return false;
    }
  }
  return false;
}

bool ConditionNotifier::Init() { return OpenOrCreate(); }

bool ConditionNotifier::OpenOrCreate() {
  // create managed_shm_
  int retry = 0;
  int shmid = 0;
  while (retry < 2) {
    shmid = shmget(key_, shm_size_, 0644 | IPC_CREAT | IPC_EXCL);
    if (shmid != -1) {
      break;
    }

    if (EINVAL == errno) {
      AINFO << "need larger space, recreate.";
      Reset();
      Remove();
      ++retry;
    } else if (EEXIST == errno) {
      ADEBUG << "shm already exist, open only.";
      return OpenOnly();
    } else {
      break;
    }
  }

  if (shmid == -1) {
    AERROR << "create shm failed, error code: " << strerror(errno);
    return false;
  }

  // attach managed_shm_
  managed_shm_ = shmat(shmid, nullptr, 0);
  if (managed_shm_ == reinterpret_cast<void*>(-1)) {
    AERROR << "attach shm failed.";
    shmctl(shmid, IPC_RMID, 0);
    return false;
  }

  // create indicator_
  indicator_ = new (managed_shm_) Indicator();
  if (indicator_ == nullptr) {
    AERROR << "create indicator failed.";
    shmdt(managed_shm_);
    managed_shm_ = nullptr;
    shmctl(shmid, IPC_RMID, 0);
    return false;
  }

  ADEBUG << "open or create true.";
  return true;
}

bool ConditionNotifier::OpenOnly() {
  // get managed_shm_
  int shmid = shmget(key_, 0, 0644);
  if (shmid == -1) {
    AERROR << "get shm failed.";
    return false;
  }

  // attach managed_shm_
  managed_shm_ = shmat(shmid, nullptr, 0);
  if (managed_shm_ == reinterpret_cast<void*>(-1)) {
    AERROR << "attach shm failed.";
    return false;
  }

  // get indicator_
  indicator_ = reinterpret_cast<Indicator*>(managed_shm_);
  if (indicator_ == nullptr) {
    AERROR << "get indicator failed.";
    shmdt(managed_shm_);
    managed_shm_ = nullptr;
    return false;
  }

  ADEBUG << "open true.";
  return true;
}

bool ConditionNotifier::Remove() {
  int shmid = shmget(key_, 0, 0644);
  if (shmid == -1 || shmctl(shmid, IPC_RMID, 0) == -1) {
    AERROR << "remove shm failed, error code: " << strerror(errno);
    return false;
  }
  ADEBUG << "remove success.";

  return true;
}

void ConditionNotifier::Reset() {
  indicator_ = nullptr;
  if (managed_shm_ != nullptr) {
    shmdt(managed_shm_);
    managed_shm_ = nullptr;
  }
}

}  // namespace transport
}  // namespace cyber
}  // namespace apollo
<commit_msg>cyber: bug fix for condition notifier<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo 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 obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "cyber/transport/shm/condition_notifier.h"

#include <sys/ipc.h>
#include <sys/shm.h>
#include <thread>

#include "cyber/common/log.h"
#include "cyber/common/util.h"

namespace apollo {
namespace cyber {
namespace transport {

using common::Hash;

ConditionNotifier::ConditionNotifier() {
  key_ = static_cast<key_t>(Hash("/apollo/cyber/transport/shm/notifier"));
  ADEBUG << "condition notifier key: " << key_;
  shm_size_ = sizeof(Indicator);

  if (!Init()) {
    AERROR << "fail to init condition notifier.";
    is_shutdown_.store(true);
    return;
  }
  next_seq_ = indicator_->next_seq.load();
  ADEBUG << "next_seq: " << next_seq_;
}

ConditionNotifier::~ConditionNotifier() { Shutdown(); }

void ConditionNotifier::Shutdown() {
  if (is_shutdown_.exchange(true)) {
    return;
  }

  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  Reset();
}

bool ConditionNotifier::Notify(const ReadableInfo& info) {
  if (is_shutdown_.load()) {
    ADEBUG << "notifier is shutdown.";
    return false;
  }

  uint64_t seq = indicator_->next_seq.fetch_add(1);
  uint64_t idx = seq % kBufLength;
  indicator_->infos[idx] = info;
  indicator_->seqs[idx] = seq;

  return true;
}

bool ConditionNotifier::Listen(int timeout_ms, ReadableInfo* info) {
  if (info == nullptr) {
    AERROR << "info nullptr.";
    return false;
  }

  if (is_shutdown_.load()) {
    ADEBUG << "notifier is shutdown.";
    return false;
  }

  int timeout_us = timeout_ms * 1000;
  while (!is_shutdown_.load()) {
    uint64_t seq = indicator_->next_seq.load();
    if (seq != next_seq_) {
      auto idx = next_seq_ % kBufLength;
      auto actual_seq = indicator_->seqs[idx];
      if (actual_seq >= next_seq_) {
        next_seq_ = actual_seq;
        *info = indicator_->infos[idx];
        ++next_seq_;
        return true;
      } else {
        ADEBUG << "seq[" << next_seq_ << "] is writing, can not read now.";
      }
    }

    if (timeout_us > 0) {
      std::this_thread::sleep_for(std::chrono::microseconds(50));
      timeout_us -= 50;
    } else {
      return false;
    }
  }
  return false;
}

bool ConditionNotifier::Init() { return OpenOrCreate(); }

bool ConditionNotifier::OpenOrCreate() {
  // create managed_shm_
  int retry = 0;
  int shmid = 0;
  while (retry < 2) {
    shmid = shmget(key_, shm_size_, 0644 | IPC_CREAT | IPC_EXCL);
    if (shmid != -1) {
      break;
    }

    if (EINVAL == errno) {
      AINFO << "need larger space, recreate.";
      Reset();
      Remove();
      ++retry;
    } else if (EEXIST == errno) {
      ADEBUG << "shm already exist, open only.";
      return OpenOnly();
    } else {
      break;
    }
  }

  if (shmid == -1) {
    AERROR << "create shm failed, error code: " << strerror(errno);
    return false;
  }

  // attach managed_shm_
  managed_shm_ = shmat(shmid, nullptr, 0);
  if (managed_shm_ == reinterpret_cast<void*>(-1)) {
    AERROR << "attach shm failed.";
    shmctl(shmid, IPC_RMID, 0);
    return false;
  }

  // create indicator_
  indicator_ = new (managed_shm_) Indicator();
  if (indicator_ == nullptr) {
    AERROR << "create indicator failed.";
    shmdt(managed_shm_);
    managed_shm_ = nullptr;
    shmctl(shmid, IPC_RMID, 0);
    return false;
  }

  ADEBUG << "open or create true.";
  return true;
}

bool ConditionNotifier::OpenOnly() {
  // get managed_shm_
  int shmid = shmget(key_, 0, 0644);
  if (shmid == -1) {
    AERROR << "get shm failed.";
    return false;
  }

  // attach managed_shm_
  managed_shm_ = shmat(shmid, nullptr, 0);
  if (managed_shm_ == reinterpret_cast<void*>(-1)) {
    AERROR << "attach shm failed.";
    return false;
  }

  // get indicator_
  indicator_ = reinterpret_cast<Indicator*>(managed_shm_);
  if (indicator_ == nullptr) {
    AERROR << "get indicator failed.";
    shmdt(managed_shm_);
    managed_shm_ = nullptr;
    return false;
  }

  ADEBUG << "open true.";
  return true;
}

bool ConditionNotifier::Remove() {
  int shmid = shmget(key_, 0, 0644);
  if (shmid == -1 || shmctl(shmid, IPC_RMID, 0) == -1) {
    AERROR << "remove shm failed, error code: " << strerror(errno);
    return false;
  }
  ADEBUG << "remove success.";

  return true;
}

void ConditionNotifier::Reset() {
  indicator_ = nullptr;
  if (managed_shm_ != nullptr) {
    shmdt(managed_shm_);
    managed_shm_ = nullptr;
  }
}

}  // namespace transport
}  // namespace cyber
}  // namespace apollo
<|endoftext|>


<commit_before>/**
 * base-n, 1.0
 * Copyright (C) 2012 Andrzej Zawadzki (azawadzki@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
**/
#ifndef BASEN_HPP
#define BASEN_HPP

#include <algorithm>
#include <cctype>
#include <cassert>
#include <cstring>

namespace bn
{

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out);

namespace impl
{

const int Error = -1;

namespace {

char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 8);
    // shift extracted bits to the beginning of the byte
    char t1 = value >> (8 - bits_count - start_bit);
    // mask out bits on the left
    char t2 = t1 & ~(0xff << bits_count);
    return t2;
}

char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 16);
    size_t bits_count_in_previous = 8 - start_bit;
    size_t bits_count_in_next = bits_count - bits_count_in_previous;
    char t1 = previous << bits_count_in_next;
    char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
    return (t1 | t2) & ~(0xff << bits_count);
}

}

struct b16_conversion_traits
{
    static size_t group_length()
    {
       return 4;
    }

    static char encode(unsigned int index)
    {
        const char* const dictionary = "0123456789ABCDEF";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        if (c >= '0' && c <= '9') {
            return c - '0';
        } else if (c >= 'A' && c <= 'F') {
            return c - 'A' + 10;
        }
        return Error;
    }
};

struct b32_conversion_traits
{
    static size_t group_length()
    {
       return 5;
    }

    static char encode(unsigned int index)
    {
        const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= '2' && c <= '7') {
            return c - '2' + 26;
        }
        return Error;
    }
};

struct b64_conversion_traits
{
    static size_t group_length()
    {
       return 6;
    }

    static char encode(unsigned int index)
    {
        const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        const int alph_len = 26;
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= 'a' && c <= 'z') {
            return c - 'a' + alph_len * 1;
        } else if (c >= '0' && c <= '9') {
            return c - '0' + alph_len * 2;
        } else if (c == '+') {
            return c - '+' + alph_len * 2 + 10;
        } else if (c == '/') {
            return c - '/' + alph_len * 2 + 11;
        }
        return Error;
    }
};

template<class ConversionTraits, class Iter1, class Iter2>
void decode(Iter1 start, Iter1 end, Iter2 out)
{
    Iter1 iter = start;
    size_t output_current_bit = 0;
    char buffer = 0;

    while (iter != end) {
        if (std::isspace(*iter)) {
            ++iter;
            continue;
        }
        char value = ConversionTraits::decode(*iter);
        if (value == Error) {
            // malformed data, but let's go on...
            ++iter;
            continue;
        }
        size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
        if (bits_in_current_byte == ConversionTraits::group_length()) {
            // the value fits within current byte, so we can extract it directly
            buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
            output_current_bit += ConversionTraits::group_length();
            // check if we filled up current byte completely; in such case we flush output and continue
            if (output_current_bit == 8) {
                *out++ = buffer;
                buffer = 0;
                output_current_bit = 0;
            }
        } else {
            // the value spans across the current and the next byte
            size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
            // fill the current byte and flush it to our output
            buffer |= value >> bits_in_next_byte;
            *out++ = buffer;
            buffer = 0;
            // save the remainder of our value in the buffer; it will be flushed
            // during next iterations
            buffer |= value << (8 - bits_in_next_byte);
            output_current_bit = bits_in_next_byte;
        }
        ++iter;
    }
}

template<class ConversionTraits, class Iter1, class Iter2>
void encode(Iter1 start, Iter1 end, Iter2 out)
{
    Iter1 iter = start;
    size_t start_bit = 0;
    bool has_backlog = false;
    char backlog = 0;

    while (has_backlog || iter != end) {
        if (!has_backlog) {
            if (start_bit + ConversionTraits::group_length() < 8) {
                // the value fits within single byte, so we can extract it
                // directly
                char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
                *out++ = ConversionTraits::encode(v);
                // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
                // to the next byte
                start_bit += ConversionTraits::group_length();
            } else {
                // our bits are spanning across byte border; we need to keep the
                // starting point and move over to next byte.
                backlog = *iter++;
                has_backlog = true;
            }
        } else {
            // encode value which is made from bits spanning across byte
            // boundary
            char v;
            if (iter == end)
                 v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
            else
                 v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
            *out++ = ConversionTraits::encode(v);
            has_backlog = false;
            start_bit = (start_bit + ConversionTraits::group_length()) % 8;
        }
    }
}

} // impl

using namespace bn::impl;

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b64_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b64_conversion_traits>(start, end, out);
}

} // bn

#endif // BASEN_HPP
<commit_msg>Fixing SVACE error on 3rd party template<commit_after>/**
 * base-n, 1.0
 * Copyright (C) 2012 Andrzej Zawadzki (azawadzki@gmail.com)
 *
 * 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.
**/

/*
 * In the original file, static analysis complains about return type from decode methods
 * not being testable against Error constant (due to difference of type sizes).
 *
 * Modified decode methods to return error through an out parameter instead.
 */

#ifndef BASEN_HPP
#define BASEN_HPP

#include <algorithm>
#include <cctype>
#include <cassert>
#include <cstring>

namespace bn
{

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out);

namespace impl
{

const int Error = -1;

namespace {

char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 8);
    // shift extracted bits to the beginning of the byte
    char t1 = value >> (8 - bits_count - start_bit);
    // mask out bits on the left
    char t2 = t1 & ~(0xff << bits_count);
    return t2;
}

char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 16);
    size_t bits_count_in_previous = 8 - start_bit;
    size_t bits_count_in_next = bits_count - bits_count_in_previous;
    char t1 = previous << bits_count_in_next;
    char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
    return (t1 | t2) & ~(0xff << bits_count);
}

}

struct b16_conversion_traits
{
    static size_t group_length()
    {
       return 4;
    }

    static char encode(unsigned int index)
    {
        const char* const dictionary = "0123456789ABCDEF";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    /*
     * In the original file, error code was passed through return value, but used int -1 (out of range of char).
     * Separated error value from return value by using out parameter.
     */
    static char decode(char c, bool& error)
    {
        error=false;
        if (c >= '0' && c <= '9') {
            return c - '0';
        } else if (c >= 'A' && c <= 'F') {
            return c - 'A' + 10;
        }
        error=true;
        return 0;
    }
};

struct b32_conversion_traits
{
    static size_t group_length()
    {
       return 5;
    }

    static char encode(unsigned int index)
    {
        const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    /*
     * In the original file, error code was passed through return value, but used int -1 (out of range of char).
     * Separated error value from return value by using out parameter.
     */
    static char decode(char c, bool& error)
    {
        error=false;
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= '2' && c <= '7') {
            return c - '2' + 26;
        }
        error=true;
        return 0;
    }
};

struct b64_conversion_traits
{
    static size_t group_length()
    {
       return 6;
    }

    static char encode(unsigned int index)
    {
        const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    /*
     * In the original file, error code was passed through return value, but used int -1 (out of range of char).
     * Separated error value from return value by using out parameter.
     */
    static char decode(char c, bool& error)
    {
        error=false;
        const int alph_len = 26;
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= 'a' && c <= 'z') {
            return c - 'a' + alph_len * 1;
        } else if (c >= '0' && c <= '9') {
            return c - '0' + alph_len * 2;
        } else if (c == '+') {
            return c - '+' + alph_len * 2 + 10;
        } else if (c == '/') {
            return c - '/' + alph_len * 2 + 11;
        }
        error=true;
        return 0;
    }
};

template<class ConversionTraits, class Iter1, class Iter2>
void decode(Iter1 start, Iter1 end, Iter2 out)
{
    Iter1 iter = start;
    size_t output_current_bit = 0;
    char buffer = 0;

    while (iter != end) {
        if (std::isspace(*iter)) {
            ++iter;
            continue;
        }

        /*
         * In the original file, error value was out of range of return type.
         * Separated error value from return value by using out parameter.
         */
        bool error=false;
        char value = ConversionTraits::decode(*iter, error);
        if (error) {
            // malformed data, but let's go on...
            ++iter;
            continue;
        }
        size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
        if (bits_in_current_byte == ConversionTraits::group_length()) {
            // the value fits within current byte, so we can extract it directly
            buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
            output_current_bit += ConversionTraits::group_length();
            // check if we filled up current byte completely; in such case we flush output and continue
            if (output_current_bit == 8) {
                *out++ = buffer;
                buffer = 0;
                output_current_bit = 0;
            }
        } else {
            // the value spans across the current and the next byte
            size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
            // fill the current byte and flush it to our output
            buffer |= value >> bits_in_next_byte;
            *out++ = buffer;
            buffer = 0;
            // save the remainder of our value in the buffer; it will be flushed
            // during next iterations
            buffer |= value << (8 - bits_in_next_byte);
            output_current_bit = bits_in_next_byte;
        }
        ++iter;
    }
}

template<class ConversionTraits, class Iter1, class Iter2>
void encode(Iter1 start, Iter1 end, Iter2 out)
{
    Iter1 iter = start;
    size_t start_bit = 0;
    bool has_backlog = false;
    char backlog = 0;

    while (has_backlog || iter != end) {
        if (!has_backlog) {
            if (start_bit + ConversionTraits::group_length() < 8) {
                // the value fits within single byte, so we can extract it
                // directly
                char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
                *out++ = ConversionTraits::encode(v);
                // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
                // to the next byte
                start_bit += ConversionTraits::group_length();
            } else {
                // our bits are spanning across byte border; we need to keep the
                // starting point and move over to next byte.
                backlog = *iter++;
                has_backlog = true;
            }
        } else {
            // encode value which is made from bits spanning across byte
            // boundary
            char v;
            if (iter == end)
                 v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
            else
                 v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
            *out++ = ConversionTraits::encode(v);
            has_backlog = false;
            start_bit = (start_bit + ConversionTraits::group_length()) % 8;
        }
    }
}

} // impl

using namespace bn::impl;

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b64_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b64_conversion_traits>(start, end, out);
}

} // bn

#endif // BASEN_HPP
<|endoftext|>