<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.                  *
 **************************************************************************/

/* $Id$ */

//_________________________________________________________________________
// Implementation version v1 of EMCAL Manager class
// An object of this class does not produce digits
// It is the one to use if you do want to produce outputs in TREEH
//
//*-- Author: Sahal Yacoob (LBL /UCT)
//*--       : Jennifer Klay (LBL)

// This Class not stores information on all particles prior to EMCAL entry - in order to facilitate analysis.
// This is done by setting fIShunt =2, and flagging all parents of particles entering the EMCAL.

// 15/02/2002 .... Yves Schutz
//  1. fSamplingFraction and fLayerToPreshowerRatio have been removed
//  2. Timing signal is collected and added to hit

// --- ROOT system ---
#include "TPGON.h"
#include "TTUBS.h"
#include "TNode.h"
#include "TRandom.h"
#include "TTree.h"
#include "TGeometry.h"
#include "TParticle.h"

// --- Standard library ---

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <Rstrstream.h>
#include <Riostream.h>
#include <math.h>

// --- AliRoot header files ---

#include "AliEMCALv1.h"
#include "AliEMCALHit.h"
#include "AliEMCALGeometry.h"
#include "AliConst.h"
#include "AliRun.h"

ClassImp(AliEMCALv1)

//______________________________________________________________________
AliEMCALv1::AliEMCALv1():AliEMCALv0(){
  // ctor

}

//______________________________________________________________________
AliEMCALv1::AliEMCALv1(const char *name, const char *title):
    AliEMCALv0(name,title){
    // Standard Creator.

    fHits= new TClonesArray("AliEMCALHit",1000);
    gAlice->AddHitList(fHits);

    fNhits = 0;
    fIshunt     =  2; // All hits are associated with particles entering the calorimeter
}

//______________________________________________________________________
AliEMCALv1::~AliEMCALv1(){
    // dtor

    if ( fHits) {
	fHits->Delete();
	delete fHits;
	fHits = 0;
    }
}
//______________________________________________________________________
void AliEMCALv1::AddHit(Int_t shunt, Int_t primary, Int_t tracknumber, Int_t iparent, Float_t ienergy,
			Int_t id, Float_t * hits,Float_t * p){
    // Add a hit to the hit list.
    // An EMCAL hit is the sum of all hits in a tower section (PRE, ECAL, HCAL)
    //   originating from the same entering particle
    Int_t hitCounter;

    AliEMCALHit *newHit;
    AliEMCALHit *curHit;
    Bool_t deja = kFALSE;

    newHit = new AliEMCALHit(shunt, primary, tracknumber, iparent, ienergy, id, hits, p);
    for ( hitCounter = fNhits-1; hitCounter >= 0 && !deja; hitCounter-- ) {
	curHit = (AliEMCALHit*) (*fHits)[hitCounter];
	// We add hits with the same tracknumber, while GEANT treats
	// primaries succesively
	if(curHit->GetPrimary() != primary)
	  break;
	if( *curHit == *newHit ) {
	    *curHit = *curHit + *newHit;
	    deja = kTRUE;
	} // end if
    } // end for hitCounter

    if ( !deja ) {
	new((*fHits)[fNhits]) AliEMCALHit(*newHit);
	fNhits++;
    } // end if

    delete newHit;
}
//______________________________________________________________________
void AliEMCALv1::StepManager(void){
  // Accumulates hits as long as the track stays in a single
  // crystal or PPSD gas Cell

  Int_t          id[2];           // (layer, phi, Eta) indices
  // position wrt MRS and energy deposited
  Float_t        xyzte[5]={0.,0.,0.,0.,0.};// position wrt MRS, time and energy deposited
  Float_t        pmom[4]={0.,0.,0.,0.};
  TLorentzVector pos; // Lorentz vector of the track current position.
  TLorentzVector mom; // Lorentz vector of the track current momentum.
  Int_t tracknumber =  gAlice->CurrentTrack();
  Int_t primary = 0;
  static Int_t iparent = 0;
  static Float_t ienergy = 0;
  Int_t copy = 0;

  AliEMCALGeometry * geom = GetGeometry() ;

  if(gMC->IsTrackEntering() && (strcmp(gMC->CurrentVolName(),"XALU") == 0)){ // This Particle in enterring the Calorimeter
    gMC->TrackPosition(pos) ;
    xyzte[0] = pos[0] ;
    xyzte[1] = pos[1] ;
    xyzte[2] = pos[2] ;
    if ( (xyzte[0]*xyzte[0] + xyzte[1]*xyzte[1])
	 <  (geom->GetEnvelop(0)+geom->GetGap2Active()+1.5 )*(geom->GetEnvelop(0)+geom->GetGap2Active()+1.5 ) ) {
      iparent = tracknumber;
      gMC->TrackMomentum(mom);
      ienergy = mom[3];
      TParticle * part = 0 ;
      Int_t parent = iparent ;
      while ( parent != -1 ) { // <------------- flags this particle to be kept and
	//all the ancestors of this particle
	part = gAlice->Particle(parent) ;
	part->SetBit(kKeepBit);
	parent = part->GetFirstMother() ;
      }
    }
  }
  if(gMC->CurrentVolID(copy) == gMC->VolId("XPHI") ) { // We are in a Scintillator Layer

    Float_t depositedEnergy ;

    if( (depositedEnergy = gMC->Edep()) > 0.){// Track is inside a scintillator and deposits some energy

      gMC->TrackPosition(pos);
      xyzte[0] = pos[0];
      xyzte[1] = pos[1];
      xyzte[2] = pos[2];
      xyzte[3] = gMC->TrackTime() ;

      gMC->TrackMomentum(mom);
      pmom[0] = mom[0];
      pmom[1] = mom[1];
      pmom[2] = mom[2];
      pmom[3] = mom[3];

      gMC->CurrentVolOffID(1, id[0]); // get the POLY copy number;
      gMC->CurrentVolID(id[1]); // get the phi number inside the layer

      Int_t tower = (id[0]-1) % geom->GetNZ() + 1 + (id[1] - 1) * 96 ;
      Int_t layer = static_cast<Int_t>((id[0]-1)/(geom->GetNZ())) + 1 ;
      Int_t absid = tower ;
      if (layer <= geom->GetNPRLayers() )
	absid += geom->GetNZ() * geom->GetNPhi() ;
      else if (layer > geom->GetNECLayers() )
	absid += 2 * geom->GetNZ() * geom->GetNPhi() ;
      else {
	Int_t nlayers = geom->GetNPRLayers()+ geom->GetNECLayers()+ geom->GetNHCLayers() ;
	if (layer > nlayers)
	  Fatal("StepManager", "Wrong calculation of layer number: layer = %d > %d\n", layer, nlayers) ;
      }

      Float_t lightYield =  depositedEnergy ;
					     ;
      xyzte[4] = lightYield  ;

      primary = gAlice->GetPrimary(tracknumber);

      if (gDebug == 2)
	Info("StepManager", "id0 = %d, id1 = %d, absid = %d tower = %d layer = %d energy = %f\n", id[0], id[1], absid, tower, layer, xyzte[4]) ;

      AddHit(fIshunt, primary,tracknumber, iparent, ienergy, absid, xyzte, pmom);
    } // there is deposited energy
  }
}
<commit_msg>correct in the StepManager the calculation of the tower id<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.                  *
 **************************************************************************/

/* $Id$ */

//_________________________________________________________________________
// Implementation version v1 of EMCAL Manager class
// An object of this class does not produce digits
// It is the one to use if you do want to produce outputs in TREEH
//
//*-- Author: Sahal Yacoob (LBL /UCT)
//*--       : Jennifer Klay (LBL)

// This Class not stores information on all particles prior to EMCAL entry - in order to facilitate analysis.
// This is done by setting fIShunt =2, and flagging all parents of particles entering the EMCAL.

// 15/02/2002 .... Yves Schutz
//  1. fSamplingFraction and fLayerToPreshowerRatio have been removed
//  2. Timing signal is collected and added to hit

// --- ROOT system ---
#include "TPGON.h"
#include "TTUBS.h"
#include "TNode.h"
#include "TRandom.h"
#include "TTree.h"
#include "TGeometry.h"
#include "TParticle.h"

// --- Standard library ---

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <Rstrstream.h>
#include <Riostream.h>
#include <math.h>

// --- AliRoot header files ---

#include "AliEMCALv1.h"
#include "AliEMCALHit.h"
#include "AliEMCALGeometry.h"
#include "AliConst.h"
#include "AliRun.h"

ClassImp(AliEMCALv1)

//______________________________________________________________________
AliEMCALv1::AliEMCALv1():AliEMCALv0(){
  // ctor

}

//______________________________________________________________________
AliEMCALv1::AliEMCALv1(const char *name, const char *title):
    AliEMCALv0(name,title){
    // Standard Creator.

    fHits= new TClonesArray("AliEMCALHit",1000);
    gAlice->AddHitList(fHits);

    fNhits = 0;
    fIshunt     =  2; // All hits are associated with particles entering the calorimeter
}

//______________________________________________________________________
AliEMCALv1::~AliEMCALv1(){
    // dtor

    if ( fHits) {
	fHits->Delete();
	delete fHits;
	fHits = 0;
    }
}
//______________________________________________________________________
void AliEMCALv1::AddHit(Int_t shunt, Int_t primary, Int_t tracknumber, Int_t iparent, Float_t ienergy,
			Int_t id, Float_t * hits,Float_t * p){
    // Add a hit to the hit list.
    // An EMCAL hit is the sum of all hits in a tower section (PRE, ECAL, HCAL)
    //   originating from the same entering particle
    Int_t hitCounter;

    AliEMCALHit *newHit;
    AliEMCALHit *curHit;
    Bool_t deja = kFALSE;

    newHit = new AliEMCALHit(shunt, primary, tracknumber, iparent, ienergy, id, hits, p);
    for ( hitCounter = fNhits-1; hitCounter >= 0 && !deja; hitCounter-- ) {
	curHit = (AliEMCALHit*) (*fHits)[hitCounter];
	// We add hits with the same tracknumber, while GEANT treats
	// primaries succesively
	if(curHit->GetPrimary() != primary)
	  break;
	if( *curHit == *newHit ) {
	    *curHit = *curHit + *newHit;
	    deja = kTRUE;
	} // end if
    } // end for hitCounter

    if ( !deja ) {
	new((*fHits)[fNhits]) AliEMCALHit(*newHit);
	fNhits++;
    } // end if

    delete newHit;
}
//______________________________________________________________________
void AliEMCALv1::StepManager(void){
  // Accumulates hits as long as the track stays in a single
  // crystal or PPSD gas Cell

  Int_t          id[2];           // (layer, phi, Eta) indices
  // position wrt MRS and energy deposited
  Float_t        xyzte[5]={0.,0.,0.,0.,0.};// position wrt MRS, time and energy deposited
  Float_t        pmom[4]={0.,0.,0.,0.};
  TLorentzVector pos; // Lorentz vector of the track current position.
  TLorentzVector mom; // Lorentz vector of the track current momentum.
  Int_t tracknumber =  gAlice->CurrentTrack();
  Int_t primary = 0;
  static Int_t iparent = 0;
  static Float_t ienergy = 0;
  Int_t copy = 0;

  AliEMCALGeometry * geom = GetGeometry() ;

  if(gMC->IsTrackEntering() && (strcmp(gMC->CurrentVolName(),"XALU") == 0)){ // This Particle in enterring the Calorimeter
    gMC->TrackPosition(pos) ;
    xyzte[0] = pos[0] ;
    xyzte[1] = pos[1] ;
    xyzte[2] = pos[2] ;
    if ( (xyzte[0]*xyzte[0] + xyzte[1]*xyzte[1])
	 <  (geom->GetEnvelop(0)+geom->GetGap2Active()+1.5 )*(geom->GetEnvelop(0)+geom->GetGap2Active()+1.5 ) ) {
      iparent = tracknumber;
      gMC->TrackMomentum(mom);
      ienergy = mom[3];
      TParticle * part = 0 ;
      Int_t parent = iparent ;
      while ( parent != -1 ) { // <------------- flags this particle to be kept and
	//all the ancestors of this particle
	part = gAlice->Particle(parent) ;
	part->SetBit(kKeepBit);
	parent = part->GetFirstMother() ;
      }
    }
  }
  if(gMC->CurrentVolID(copy) == gMC->VolId("XPHI") ) { // We are in a Scintillator Layer

    Float_t depositedEnergy ;

    if( (depositedEnergy = gMC->Edep()) > 0.){// Track is inside a scintillator and deposits some energy

      gMC->TrackPosition(pos);
      xyzte[0] = pos[0];
      xyzte[1] = pos[1];
      xyzte[2] = pos[2];
      xyzte[3] = gMC->TrackTime() ;

      gMC->TrackMomentum(mom);
      pmom[0] = mom[0];
      pmom[1] = mom[1];
      pmom[2] = mom[2];
      pmom[3] = mom[3];

      gMC->CurrentVolOffID(1, id[0]); // get the POLY copy number;
      gMC->CurrentVolID(id[1]); // get the phi number inside the layer

      Int_t tower = (id[0]-1) % geom->GetNZ() + 1 + (id[1] - 1) * geom->GetNZ() ;
      Int_t layer = static_cast<Int_t>((id[0]-1)/(geom->GetNZ())) + 1 ;
      Int_t absid = tower ;
      if (layer <= geom->GetNPRLayers() )
	absid += geom->GetNZ() * geom->GetNPhi() ;
      else if (layer > geom->GetNECLayers() )
	absid += 2 * geom->GetNZ() * geom->GetNPhi() ;
      else {
	Int_t nlayers = geom->GetNPRLayers()+ geom->GetNECLayers()+ geom->GetNHCLayers() ;
	if (layer > nlayers)
	  Fatal("StepManager", "Wrong calculation of layer number: layer = %d > %d\n", layer, nlayers) ;
      }

      Float_t lightYield =  depositedEnergy ;
					     ;
      xyzte[4] = lightYield  ;

      primary = gAlice->GetPrimary(tracknumber);

      if (gDebug == 2)
	Info("StepManager", "id0 = %d, id1 = %d, absid = %d tower = %d layer = %d energy = %f\n", id[0], id[1], absid, tower, layer, xyzte[4]) ;

      AddHit(fIshunt, primary,tracknumber, iparent, ienergy, absid, xyzte, pmom);
    } // there is deposited energy
  }
}
<|endoftext|>


<commit_before>#include "pinboost_debug.h"

#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <cstdlib>

bool pinboost_do_debug = false;
static std::string pinboost_name = "PINBOOST";

static EXCEPT_HANDLING_RESULT pinboost_exceptionhandler(THREADID threadid, EXCEPTION_INFO *pExceptInfo, PHYSICAL_CONTEXT *pPhysCtxt, VOID *v)
{
   static bool in_handler = false;

   std::cerr << "["<<pinboost_name<<"] Internal exception:" << PIN_ExceptionToString(pExceptInfo) << std::endl;

   if (!in_handler)
   {
      // Avoid recursion when the code below generates a new exception
      in_handler = true;

      pinboost_debugme(threadid);
   }

   return EHR_CONTINUE_SEARCH;
}

void pinboost_register(const char* name)
{
   PIN_AddInternalExceptionHandler(pinboost_exceptionhandler, NULL);
   if (name)
      pinboost_name = name;
   pinboost_do_debug = true;
}

void pinboost_debugme(THREADID threadid)
{
   if (getenv("SNIPER_ROOT") == NULL)
   {
      std::cerr << "[" << pinboost_name << "] SNIPER_ROOT not set, cannot launch debugger." << std::endl;
      return;
   }

   // If we are the faulting thread, pass in our tid so the debug script can mark us
   pid_t tid = PIN_ThreadId() == threadid ? PIN_GetTid() : 0;

   char cmd[1024];
   sprintf(cmd, "%s/tools/pinboost_debugme.py %d %d", getenv("SNIPER_ROOT"), getpid(), tid);

   int rc = system(cmd);
   if (rc)
   {
      std::cerr << "[" << pinboost_name << "] Failed to start debugging session." << std::endl;
      return;
   }

   // Give the debugger some time to attach, after that, fall through
   sleep(5);
}

void pinboost_assert_fail(const char *__assertion, const char *__file, unsigned int __line, const char *__function)
{
   std::cerr << "[" << pinboost_name << "] " << __file << ":" << __line << ": " <<__function
             << ": Assertion `" << __assertion << "' failed." << std::endl;
   if (pinboost_do_debug)
      pinboost_debugme(PIN_ThreadId());
   exit(0);
}
<commit_msg>[sift_recorder] Improve exception handling - Ignore exceptions occuring after timing model says we're done - Ignore double exceptions (either from signal handler or from another thread)<commit_after>#include "pinboost_debug.h"

#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <cstdlib>

bool assert_ignore();

bool pinboost_do_debug = false;
static std::string pinboost_name = "PINBOOST";

static EXCEPT_HANDLING_RESULT pinboost_exceptionhandler(THREADID threadid, EXCEPTION_INFO *pExceptInfo, PHYSICAL_CONTEXT *pPhysCtxt, VOID *v)
{
   static bool in_handler = false;

   if (assert_ignore())
   {
      // Timing model says it's done, ignore assert and pretend to have exited cleanly
      exit(0);
   }

   std::cerr << "["<<pinboost_name<<"] Internal exception:" << PIN_ExceptionToString(pExceptInfo) << std::endl;

   if (!in_handler)
   {
      // Avoid recursion when the code below generates a new exception
      in_handler = true;

      pinboost_debugme(threadid);
   }
   else
   {
      // Error occurred while handling another error (either in the exception handler, or in another thread)
      // Debug session should already be started, let's ignore this error and halt so the user can inspect the state.
      pause();
   }

   return EHR_CONTINUE_SEARCH;
}

void pinboost_register(const char* name)
{
   PIN_AddInternalExceptionHandler(pinboost_exceptionhandler, NULL);
   if (name)
      pinboost_name = name;
   pinboost_do_debug = true;
}

void pinboost_debugme(THREADID threadid)
{
   if (getenv("SNIPER_ROOT") == NULL)
   {
      std::cerr << "[" << pinboost_name << "] SNIPER_ROOT not set, cannot launch debugger." << std::endl;
      return;
   }

   // If we are the faulting thread, pass in our tid so the debug script can mark us
   pid_t tid = PIN_ThreadId() == threadid ? PIN_GetTid() : 0;

   char cmd[1024];
   sprintf(cmd, "%s/tools/pinboost_debugme.py %d %d", getenv("SNIPER_ROOT"), getpid(), tid);

   int rc = system(cmd);
   if (rc)
   {
      std::cerr << "[" << pinboost_name << "] Failed to start debugging session." << std::endl;
      return;
   }

   // Give the debugger some time to attach, after that, fall through
   sleep(5);
}

void pinboost_assert_fail(const char *__assertion, const char *__file, unsigned int __line, const char *__function)
{
   std::cerr << "[" << pinboost_name << "] " << __file << ":" << __line << ": " <<__function
             << ": Assertion `" << __assertion << "' failed." << std::endl;
   if (pinboost_do_debug)
      pinboost_debugme(PIN_ThreadId());
   exit(0);
}
<|endoftext|>


<commit_before>// sample.hxx -- Sound sample encapsulation class
//
// Written by Curtis Olson, started April 2004.
//
// Copyright (C) 2004  Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id$

/**
 * \file sample.hxx
 * Provides a sound sample encapsulation
 */

#ifndef _SG_SAMPLE_HXX
#define _SG_SAMPLE_HXX 1

#ifndef __cplusplus
# error This library requires C++
#endif

#include <string>

#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/SGMath.hxx>

// #include <plib/sg.h>

/**
 * manages everything we need to know for an individual sound sample
 */

class SGSoundSample : public SGReferenced {

private:

    // Position of the source sound.
    SGVec3d _absolute_pos;	// absolute position
    SGVec3f _relative_pos;	// position relative to the base position
    SGVec3d _direction;		// orientation offset
    SGVec3d _velocity;		// Velocity of the source sound.

    // The position and orientation of the sound
    SGGeod _base_pos;
    SGQuatd _orientation;	// base orientation

    std::string _sample_name;
    unsigned char *_data;

    // configuration values
    int _format;
    int _size;
    int _freq;

    // Buffers hold sound data.
    bool _valid_buffer;
    unsigned int _buffer;

    // Sources are points emitting sound.
    bool _valid_source;
    unsigned int _source;

    // The orientation of the sound (direction and cut-off angles)
    float _inner_angle;
    float _outer_angle;
    float _outer_gain;

    float _pitch;
    float _volume;
    float _master_volume;
    float _reference_dist;
    float _max_dist;
    bool _loop;

    bool _playing;
    bool _changed;
    bool _static_changed;
    bool _is_file;

    SGVec3f _orivec;
    void update_absolute_position();

public:

     /**
      * Empty constructor, can be used to read data to the systems
      * memory and not to the driver.
      */
    SGSoundSample();

    /**
     * Constructor
     * @param path Path name to sound
     * @param file File name of sound
       should usually be true unless you want to manipulate the data
       later.)
     */
    SGSoundSample( const char *path, const char *file );

    /**
     * Constructor.
     * @param _data Pointer to a memory buffer containing the sample data
       the application is responsible for freeing the buffer data.
     * @param len Byte length of array
     * @param _freq Frequency of the provided data (bytes per second)
       should usually be true unless you want to manipulate the data
       later.)
     */
    SGSoundSample( unsigned char *data, int len, int freq, int format = AL_FORMAT_MONO8 );

    ~SGSoundSample ();

    /**
     * detect wheter the sample holds the information of a sound file
     */
    inline bool is_file() const { return _is_file; }

    /**
     * Test whether this sample has a changed configuration since the last
     * call. (Calling this function resets the value).
     */
    inline bool has_changed() {
        bool b = _changed; _changed = false; return b;
    }

    inline bool has_static_data_changed() {
        bool b = _static_changed; _static_changed = false; return b;
    }

    /**
     * Start playing this sample.
     *
     * @param _loop Define whether the sound should be played in a loop.
     */
    inline void play( bool loop ) {
        _playing = true; _loop = loop; _changed = true;
    }

    /**
     * Return if the sample is looping or not.
     */
    inline bool get_looping() { return _loop; }

    /**
     * Stop playing this sample.
     *
     * @param sched A pointer to the appropriate scheduler.
     */
    inline void stop() {
        _playing = false; _changed = true;
    }

    /**
     * Play this sample once.
     * @see #play
     */
    inline void play_once() { play(false); }

    /**
     * Play this sample looped.
     * @see #play
     */
    inline void play_looped() { play(true); }

    /**
     * Test if a sample is currently playing.
     * @return true if is is playing, false otherwise.
     */
    inline bool is_playing() { return _playing; }

    /**
     * set the data associated with this sample
     */
    inline void set_data( unsigned char* data ) {
        _data = data;
    }

    /**
     * @return the data associated with this sample
     */
    inline void* get_data() const { return _data; }

    /**
     * free the data associated with this sample
     */
    inline void free_data() {
        if (_data != NULL) { delete[] _data; _data = NULL; }
    }

    /**
     * set the source id of this source
     */
    inline void set_source(unsigned int s) {
        _source = s; _valid_source = true; _changed = true;
    }

    /**
     * get the source id of this source
     */
    inline unsigned int get_source() { return _source; }

    /**
     * detect wheter the source id of the sample is valid
     */
    inline bool is_valid_source() const { return _valid_source; }

    /**
     * set the source id of the sample to invalid.
     */
    inline void no_valid_source() {
        _valid_source = false;
    }

    /**
     * set the buffer id of this source
     */
    inline void set_buffer(unsigned int b) {
        _buffer = b; _valid_buffer = true; _changed = true;
    }

    /**
     * get the buffer id of this source
     */
    inline unsigned int get_buffer() { return _buffer; }

    /**
     * detect wheter the source id of the sample is valid
     */
    inline bool is_valid_buffer() const { return _valid_buffer; }

    /**
     * set the source id of the sample to invalid.
     */
    inline void no_valid_buffer() {
        _valid_buffer = false;
    }

    /**
     * Get the current pitch setting of this sample.
     */
    inline float get_pitch() { return _pitch; }

    /**
     * Set the pitch of this sample.
     */
    inline void set_pitch( float p ) {
        _pitch = p; _changed = true;
    }

    /**
     * Get the current volume setting of this sample.
     */
    inline float get_volume() { return _volume * _master_volume; }

    /**
     * Set the master (sampel group) volume of this sample.
     */
    inline void set_master_volume( float v ) {
        _master_volume = v; _changed = true;
    }

    /**
     * Set the volume of this sample.
     */
    inline void set_volume( float v ) {
        _volume = v; _changed = true;
    }

    /**
     * Set the format of the sounds sample
     */
    inline void set_format( int format ) {
        _format = format;
    }

    /**
     * Returns the format of the sounds sample
     */
    inline int get_format() { return _format; }

    /**
     * Set the frequency of the sounds sample
     */
    inline void set_frequency( int freq ) {
        _freq = freq; _changed = true;
    }

    /**
     * Returns the frequency of the sounds sample
     */
    inline int get_frequency() { return _freq; }

    /**
     * Returns the size of the sounds sample
     */
    inline void set_size( int size ) {
        _size = size;
    }

    /**
     * Returns the size of the sounds sample
     */
    inline int get_size() const { return _size; }

    /**
     * Set position of the sound source (uses same coordinate system as opengl)
     */
    void set_relative_position( SGVec3f pos );

    /**
     * Get position of the sound source (uses same coordinate system as opengl)
     */
    inline float *get_position() const { return toVec3f(_absolute_pos).data(); }

    /**
     * Set the position of the sound source
     */
    void set_position( SGGeod pos );

    /**
     * Set the orientation of the sound source
     */
    void set_orientation( SGQuatd ori );

    /**
     * Set the relative direction of the sound source, both for direction
     * and audio cut-off angles.
     */
    void set_direction( SGVec3d dir );

    /**
     * Define the audio cone parameters for directional audio
     */
    inline void set_audio_cone( float inner, float outer, float gain ) {
        _inner_angle = inner;
        _outer_angle = outer;
        _outer_gain = gain;
        _static_changed = true;
    }

    /**
     * Get the orientation of the sound source, the inner or outer angle
     * or outer gain.
     */
    float *get_orientation() { return _orivec.data(); }
    float get_innerangle() { return _inner_angle; }
    float get_outerangle() { return _outer_angle; }
    float get_outergain() { return _outer_gain; }

    /**
     * Set velocity of the sound source (uses same coordinate system as opengl)
     */
    inline void set_velocity( SGVec3d& vel ) {
        _velocity = vel;
        _changed = true;
    }

    /**
     * Get velocity of the sound source (uses same coordinate system as opengl)
     */
    inline float *get_velocity() { return toVec3f(_velocity).data(); }

    /**
     * Set reference distance of sound (the distance where the gain
     * will be half.)
     */
    inline void set_reference_dist( float dist ) {
        _reference_dist = dist; _static_changed = true;
    }

    /**
     * Get reference distance of sound (the distance where the gain
     * will be half.)
     */
    inline float get_reference_dist() { return _reference_dist; }

    /**
     * Set maximum distance of sound (the distance where the sound is
     * no longer audible.
     */
    void set_max_dist( float dist ) {
        _max_dist = dist; _static_changed = true;
    }

    /**
     * Get maximum istance of sound (the distance where the sound is
     * no longer audible.
     */
    inline float get_max_dist() { return _max_dist; }

    /**
     * Get the name of this sample
     */
    inline std::string get_sample_name() { return _sample_name; }
};

#endif // _SG_SAMPLE_HXX

<commit_msg>_data is not an array of pointer<commit_after>// sample.hxx -- Sound sample encapsulation class
//
// Written by Curtis Olson, started April 2004.
//
// Copyright (C) 2004  Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// $Id$

/**
 * \file sample.hxx
 * Provides a sound sample encapsulation
 */

#ifndef _SG_SAMPLE_HXX
#define _SG_SAMPLE_HXX 1

#ifndef __cplusplus
# error This library requires C++
#endif

#include <string>

#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/SGMath.hxx>

// #include <plib/sg.h>

/**
 * manages everything we need to know for an individual sound sample
 */

class SGSoundSample : public SGReferenced {

private:

    // Position of the source sound.
    SGVec3d _absolute_pos;	// absolute position
    SGVec3d _relative_pos;	// position relative to the base position
    SGVec3d _direction;		// orientation offset
    SGVec3d _velocity;		// Velocity of the source sound.

    // The position and orientation of the sound
    SGGeod _base_pos;
    SGQuatd _orientation;	// base orientation

    std::string _sample_name;
    unsigned char *_data;

    // configuration values
    int _format;
    int _size;
    int _freq;

    // Buffers hold sound data.
    bool _valid_buffer;
    unsigned int _buffer;

    // Sources are points emitting sound.
    bool _valid_source;
    unsigned int _source;

    // The orientation of the sound (direction and cut-off angles)
    float _inner_angle;
    float _outer_angle;
    float _outer_gain;

    float _pitch;
    float _volume;
    float _master_volume;
    float _reference_dist;
    float _max_dist;
    bool _loop;

    bool _playing;
    bool _changed;
    bool _static_changed;
    bool _is_file;

    SGVec3f _orivec;
    void update_absolute_position();

public:

     /**
      * Empty constructor, can be used to read data to the systems
      * memory and not to the driver.
      */
    SGSoundSample();

    /**
     * Constructor
     * @param path Path name to sound
     * @param file File name of sound
       should usually be true unless you want to manipulate the data
       later.)
     */
    SGSoundSample( const char *path, const char *file );

    /**
     * Constructor.
     * @param _data Pointer to a memory buffer containing the sample data
       the application is responsible for freeing the buffer data.
     * @param len Byte length of array
     * @param _freq Frequency of the provided data (bytes per second)
       should usually be true unless you want to manipulate the data
       later.)
     */
    SGSoundSample( unsigned char *data, int len, int freq, int format = AL_FORMAT_MONO8 );

    ~SGSoundSample ();

    /**
     * detect wheter the sample holds the information of a sound file
     */
    inline bool is_file() const { return _is_file; }

    /**
     * Test whether this sample has a changed configuration since the last
     * call. (Calling this function resets the value).
     */
    inline bool has_changed() {
        bool b = _changed; _changed = false; return b;
    }

    inline bool has_static_data_changed() {
        bool b = _static_changed; _static_changed = false; return b;
    }

    /**
     * Start playing this sample.
     *
     * @param _loop Define whether the sound should be played in a loop.
     */
    inline void play( bool loop ) {
        _playing = true; _loop = loop; _changed = true;
    }

    /**
     * Return if the sample is looping or not.
     */
    inline bool get_looping() { return _loop; }

    /**
     * Stop playing this sample.
     *
     * @param sched A pointer to the appropriate scheduler.
     */
    inline void stop() {
        _playing = false; _changed = true;
    }

    /**
     * Play this sample once.
     * @see #play
     */
    inline void play_once() { play(false); }

    /**
     * Play this sample looped.
     * @see #play
     */
    inline void play_looped() { play(true); }

    /**
     * Test if a sample is currently playing.
     * @return true if is is playing, false otherwise.
     */
    inline bool is_playing() { return _playing; }

    /**
     * set the data associated with this sample
     */
    inline void set_data( unsigned char* data ) {
        _data = data;
    }

    /**
     * @return the data associated with this sample
     */
    inline void* get_data() const { return _data; }

    /**
     * free the data associated with this sample
     */
    inline void free_data() {
        if (_data != NULL) { delete _data; _data = NULL; }
    }

    /**
     * set the source id of this source
     */
    inline void set_source(unsigned int s) {
        _source = s; _valid_source = true; _changed = true;
    }

    /**
     * get the source id of this source
     */
    inline unsigned int get_source() { return _source; }

    /**
     * detect wheter the source id of the sample is valid
     */
    inline bool is_valid_source() const { return _valid_source; }

    /**
     * set the source id of the sample to invalid.
     */
    inline void no_valid_source() {
        _valid_source = false;
    }

    /**
     * set the buffer id of this source
     */
    inline void set_buffer(unsigned int b) {
        _buffer = b; _valid_buffer = true; _changed = true;
    }

    /**
     * get the buffer id of this source
     */
    inline unsigned int get_buffer() { return _buffer; }

    /**
     * detect wheter the source id of the sample is valid
     */
    inline bool is_valid_buffer() const { return _valid_buffer; }

    /**
     * set the source id of the sample to invalid.
     */
    inline void no_valid_buffer() {
        _valid_buffer = false;
    }

    /**
     * Get the current pitch setting of this sample.
     */
    inline float get_pitch() { return _pitch; }

    /**
     * Set the pitch of this sample.
     */
    inline void set_pitch( float p ) {
        _pitch = p; _changed = true;
    }

    /**
     * Get the current volume setting of this sample.
     */
    inline float get_volume() { return _volume * _master_volume; }

    /**
     * Set the master (sampel group) volume of this sample.
     */
    inline void set_master_volume( float v ) {
        _master_volume = v; _changed = true;
    }

    /**
     * Set the volume of this sample.
     */
    inline void set_volume( float v ) {
        _volume = v; _changed = true;
    }

    /**
     * Set the format of the sounds sample
     */
    inline void set_format( int format ) {
        _format = format;
    }

    /**
     * Returns the format of the sounds sample
     */
    inline int get_format() { return _format; }

    /**
     * Set the frequency of the sounds sample
     */
    inline void set_frequency( int freq ) {
        _freq = freq; _changed = true;
    }

    /**
     * Returns the frequency of the sounds sample
     */
    inline int get_frequency() { return _freq; }

    /**
     * Returns the size of the sounds sample
     */
    inline void set_size( int size ) {
        _size = size;
    }

    /**
     * Returns the size of the sounds sample
     */
    inline int get_size() const { return _size; }

    /**
     * Set position of the sound source (uses same coordinate system as opengl)
     */
    void set_relative_position( SGVec3f pos );

    /**
     * Get position of the sound source (uses same coordinate system as opengl)
     */
    inline float *get_position() const { return toVec3f(_absolute_pos).data(); }

    /**
     * Set the position of the sound source
     */
    void set_position( SGGeod pos );

    /**
     * Set the orientation of the sound source
     */
    void set_orientation( SGQuatd ori );

    /**
     * Set the relative direction of the sound source, both for direction
     * and audio cut-off angles.
     */
    void set_direction( SGVec3d dir );

    /**
     * Define the audio cone parameters for directional audio
     */
    inline void set_audio_cone( float inner, float outer, float gain ) {
        _inner_angle = inner;
        _outer_angle = outer;
        _outer_gain = gain;
        _static_changed = true;
    }

    /**
     * Get the orientation of the sound source, the inner or outer angle
     * or outer gain.
     */
    float *get_orientation() { return _orivec.data(); }
    float get_innerangle() { return _inner_angle; }
    float get_outerangle() { return _outer_angle; }
    float get_outergain() { return _outer_gain; }

    /**
     * Set velocity of the sound source (uses same coordinate system as opengl)
     */
    inline void set_velocity( SGVec3d& vel ) {
        _velocity = vel;
        _changed = true;
    }

    /**
     * Get velocity of the sound source (uses same coordinate system as opengl)
     */
    inline float *get_velocity() { return toVec3f(_velocity).data(); }

    /**
     * Set reference distance of sound (the distance where the gain
     * will be half.)
     */
    inline void set_reference_dist( float dist ) {
        _reference_dist = dist; _static_changed = true;
    }

    /**
     * Get reference distance of sound (the distance where the gain
     * will be half.)
     */
    inline float get_reference_dist() { return _reference_dist; }

    /**
     * Set maximum distance of sound (the distance where the sound is
     * no longer audible.
     */
    void set_max_dist( float dist ) {
        _max_dist = dist; _static_changed = true;
    }

    /**
     * Get maximum istance of sound (the distance where the sound is
     * no longer audible.
     */
    inline float get_max_dist() { return _max_dist; }

    /**
     * Get the name of this sample
     */
    inline std::string get_sample_name() { return _sample_name; }
};

#endif // _SG_SAMPLE_HXX

<|endoftext|>


<commit_before>/** \file    SqlUtil.cc
 *  \brief   Implementations of SQL-related utility functions.
 *  \author  Dr. Johannes Ruscheinski
 *  \author  Artur Kedzierski
 *  \author  Dr. Gordon W. Paynter
 */

/*
 *  \copyright 2002-2009 Project iVia.
 *  \copyright 2002-2009 The Regents of The University of California.
 *  \copyright 2016,2017,2019 Universitätsbibliothek Tübingen.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2 of the License,
 *  or (at your option) any later version.
 *
 *  libiViaCore is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with libiViaCore; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "SqlUtil.h"
#include <algorithm>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "StringUtil.h"
#include "TimeUtil.h"
#include "util.h"

namespace SqlUtil {

const std::string DATETIME_RANGE_MIN("1000-01-01 00:00:00");
const std::string DATETIME_RANGE_MAX("9999-12-31 23:59:59");

// reference count of open transactions
std::map<DbConnection *, TransactionGuard::Status> TransactionGuard::connection_status_;

TransactionGuard::TransactionGuard(DbConnection * const db_connection, const IsolationLevel level)
    : db_connection_(db_connection)
{
    std::string begin("START TRANSACTION");

    if (connection_status_.find(db_connection) == connection_status_.end()) {
        if (level == READ_COMMITTED)
            begin += " WITH CONSISTENT SNAPSHOT";
        db_connection_->queryOrDie(begin);
        Status status(level);
        connection_status_[db_connection] = status;
    } else {
        connection_status_[db_connection].reference_count_++;
        if (connection_status_[db_connection].level_ != level)
            logger->warning("in TransactionGuard::TransactionGuard: Inconsistent isolation level requested!");
    }
}

void TransactionGuard::rollback() {
    connection_status_[db_connection_].rolled_back_ = true;
}

TransactionGuard::~TransactionGuard() {
    if (connection_status_[db_connection_].reference_count_ == 1) {
        if (connection_status_[db_connection_].rolled_back_)
            db_connection_->queryOrDie("ROLLBACK");
        else
            db_connection_->queryOrDie("COMMIT");
    } else
        --connection_status_[db_connection_].reference_count_;
}

std::string TruncateToVarCharMaxIndexLength(const std::string &s) {
    auto truncated(s);
    if (truncated.length() > VARCHAR_UTF8_MAX_INDEX_LENGTH)
        truncated.erase(VARCHAR_UTF8_MAX_INDEX_LENGTH);

    return truncated;
}

// EscapeBlob -- Escape characters in a binary string so it can be used as a MySQL BLOB.
//
std::string &EscapeBlob(std::string * const s) {
    std::string encoded_string;
    encoded_string.reserve(s->size() * 2);

    for (const char ch : *s) {
        if (unlikely(ch == '\'' or ch == '"' or ch == '\\'))
            encoded_string += '\\';
        encoded_string += ch;
    }

    std::swap(*s, encoded_string);
    return *s;
}

std::string Unescape(std::string * const s) {
    std::string decoded_string;
    decoded_string.reserve(s->size());
    for (auto ch(s->cbegin()); ch != s->cend(); ++ch) {
        if (likely(*ch != '\\'))
            decoded_string += *ch;
        else {
            ++ch;
            if (unlikely(ch == s->cend()))
                throw std::runtime_error("SqlUtil::Unescape: unexpected end of encoded string!");

            switch (*ch) {
            case '\'':
                decoded_string += '\'';
                break;
            case '"':
                decoded_string += '"';
                break;
            case 'b':
                decoded_string += '\b';
                break;
            case 'n':
                decoded_string += '\n';
                break;
            case 'r':
                decoded_string += '\r';
                break;
            case 't':
                decoded_string += '\t';
                break;
            case '\\':
                decoded_string += '\\';
                break;
            default:
                throw std::runtime_error("SqlUtil::Unescape: improperly encoded string! (ch == "
                                         + StringUtil::CStyleEscape(*ch) + ")");
            }
        }
    }

    return (*s = decoded_string);
}

tm DatetimeToTm(const std::string &datetime) {
    if (not IsValidDatetime(datetime))
        throw std::runtime_error("in SqlUtil::DateToTm: invalid \"datetime\" argument \"" + datetime + "\"!");

    // current time format is YYYY-MM-DD hh:mm:ss
    tm time_struct;
    time_struct.tm_year  = std::atol(datetime.substr(0, 4).c_str()) - 1900;
    time_struct.tm_mon   = std::atol(datetime.substr(5, 2).c_str()) - 1;
    time_struct.tm_mday  = std::atol(datetime.substr(8, 2).c_str());
    time_struct.tm_hour  = std::atol(datetime.substr(11, 2).c_str());
    time_struct.tm_min   = std::atol(datetime.substr(14, 2).c_str());
    time_struct.tm_sec   = std::atol(datetime.substr(17, 2).c_str());
    time_struct.tm_isdst = -1; // Don't *ever* change this!!

    return time_struct;
}

time_t DatetimeToTimeT(const std::string &datetime) {
    tm time_struct(DatetimeToTm(datetime));
    errno = 0;
    const time_t ret_val(::mktime(&time_struct));
    if (unlikely(errno != 0))
        return TimeUtil::BAD_TIME_T;
    return ret_val;
}

std::string TmToDatetime(const struct tm &time_struct) {
    char sql_datetime[30 + 1];
    std::sprintf(sql_datetime, "%04u-%02u-%02u %02u:%02u:%02u", time_struct.tm_year + 1900,
                 time_struct.tm_mon + 1, time_struct.tm_mday, time_struct.tm_hour,
                 time_struct.tm_min, time_struct.tm_sec);

    return sql_datetime;
}

std::string TimeTToDatetime(const time_t time) {
    return TmToDatetime(*::gmtime(&time));
}

bool IsValidDatetime(const std::string &datetime) {
    if (datetime.length() == 10) {
        // Presumably "YYYY-MM-DD".

        unsigned year, month, day;
        if (std::sscanf(datetime.c_str(), "%4u-%2u-%2u", &year, &month, &day) != 3)
            return false;

        return (year >= 1000 and year <= 9999) and (month >= 1 and month <= 12) and
            (day >= 1 and day <= 365);
    } else if (datetime.length() == 19) {
        // Presumably "YYYY-MM-DD hh:mm:ss".

        unsigned year, month, day, hour, minute, second;
        if (std::sscanf(datetime.c_str(), "%4u-%2u-%2u %2u:%2u:%2u", &year, &month, &day, &hour,
                        &minute, &second) != 6)
            return false;

        return (year >= 1000 and year <= 9999) and (month >= 1 and month <= 12) and
            (day >= 1 and day <= 365) and hour <= 23 and minute <= 59 and second <= 61;
    } else
        return false;
}

std::string GetDatetime(const long offset) {
    time_t now(std::time(NULL) + offset);
    char buf[20 + 1];
    std::strftime(buf, sizeof(buf), "%F %T", std::localtime(&now));

    return buf;
}

std::set<std::string> GetColumnNames(DbConnection * const connection, const std::string &table_name) {
    const std::string SHOW_COUMNS_STMT("SHOW COLUMNS FROM `" + table_name + "`;");
    if (not connection->query(SHOW_COUMNS_STMT))
        throw std::runtime_error("in SqlUtil::GetColumnNames: Show columns failed: " + SHOW_COUMNS_STMT
                                 + " (" + connection->getLastErrorMessage() + ")");
    DbResultSet result_set(connection->getLastResultSet());
    std::set<std::string> column_names;
    while (const DbRow row = result_set.getNextRow())
        column_names.insert(row["Field"]);

    return column_names;
}

unsigned GetTableSize(DbConnection * const connection, const std::string &table_name) {
    connection->queryOrDie("SELECT COUNT(*) FROM " + table_name);
    DbResultSet result_set(connection->getLastResultSet());
    const DbRow first_row(result_set.getNextRow());

    return StringUtil::ToUnsigned(first_row[0]);
}

ThreadSafetyGuard::ThreadSafetyGuard(const ThreadType invoker_thread)
    : invoker_thread_(invoker_thread)
{
    switch (invoker_thread_) {
    case ThreadType::MAIN_THREAD:
        if (::mysql_library_init(0, nullptr, nullptr))
            LOG_ERROR("mysql_library_init failed");
        break;
    case ThreadType::WORKER_THREAD:
        if (::mysql_thread_init())
            LOG_ERROR("mysql_thread_init failed in worker thread " + std::to_string(::pthread_self()));
        break;
    default:
        LOG_ERROR("unknown invoker thread " + std::to_string(invoker_thread_));
    }
}

ThreadSafetyGuard::~ThreadSafetyGuard() {
    switch (invoker_thread_) {
    case ThreadType::MAIN_THREAD:
        ::mysql_library_end();
        break;
    case ThreadType::WORKER_THREAD:
        ::mysql_thread_end();
        break;
    default:
        LOG_ERROR("unknown invoker thread " + std::to_string(invoker_thread_));
    }
}

} // namespace SqlUtil
<commit_msg>SqlUtil.cc: Fixed wrong function name in error message<commit_after>/** \file    SqlUtil.cc
 *  \brief   Implementations of SQL-related utility functions.
 *  \author  Dr. Johannes Ruscheinski
 *  \author  Artur Kedzierski
 *  \author  Dr. Gordon W. Paynter
 */

/*
 *  \copyright 2002-2009 Project iVia.
 *  \copyright 2002-2009 The Regents of The University of California.
 *  \copyright 2016,2017,2019 Universitätsbibliothek Tübingen.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2 of the License,
 *  or (at your option) any later version.
 *
 *  libiViaCore is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with libiViaCore; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "SqlUtil.h"
#include <algorithm>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#include "Compiler.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "StringUtil.h"
#include "TimeUtil.h"
#include "util.h"

namespace SqlUtil {

const std::string DATETIME_RANGE_MIN("1000-01-01 00:00:00");
const std::string DATETIME_RANGE_MAX("9999-12-31 23:59:59");

// reference count of open transactions
std::map<DbConnection *, TransactionGuard::Status> TransactionGuard::connection_status_;

TransactionGuard::TransactionGuard(DbConnection * const db_connection, const IsolationLevel level)
    : db_connection_(db_connection)
{
    std::string begin("START TRANSACTION");

    if (connection_status_.find(db_connection) == connection_status_.end()) {
        if (level == READ_COMMITTED)
            begin += " WITH CONSISTENT SNAPSHOT";
        db_connection_->queryOrDie(begin);
        Status status(level);
        connection_status_[db_connection] = status;
    } else {
        connection_status_[db_connection].reference_count_++;
        if (connection_status_[db_connection].level_ != level)
            logger->warning("in TransactionGuard::TransactionGuard: Inconsistent isolation level requested!");
    }
}

void TransactionGuard::rollback() {
    connection_status_[db_connection_].rolled_back_ = true;
}

TransactionGuard::~TransactionGuard() {
    if (connection_status_[db_connection_].reference_count_ == 1) {
        if (connection_status_[db_connection_].rolled_back_)
            db_connection_->queryOrDie("ROLLBACK");
        else
            db_connection_->queryOrDie("COMMIT");
    } else
        --connection_status_[db_connection_].reference_count_;
}

std::string TruncateToVarCharMaxIndexLength(const std::string &s) {
    auto truncated(s);
    if (truncated.length() > VARCHAR_UTF8_MAX_INDEX_LENGTH)
        truncated.erase(VARCHAR_UTF8_MAX_INDEX_LENGTH);

    return truncated;
}

// EscapeBlob -- Escape characters in a binary string so it can be used as a MySQL BLOB.
//
std::string &EscapeBlob(std::string * const s) {
    std::string encoded_string;
    encoded_string.reserve(s->size() * 2);

    for (const char ch : *s) {
        if (unlikely(ch == '\'' or ch == '"' or ch == '\\'))
            encoded_string += '\\';
        encoded_string += ch;
    }

    std::swap(*s, encoded_string);
    return *s;
}

std::string Unescape(std::string * const s) {
    std::string decoded_string;
    decoded_string.reserve(s->size());
    for (auto ch(s->cbegin()); ch != s->cend(); ++ch) {
        if (likely(*ch != '\\'))
            decoded_string += *ch;
        else {
            ++ch;
            if (unlikely(ch == s->cend()))
                throw std::runtime_error("SqlUtil::Unescape: unexpected end of encoded string!");

            switch (*ch) {
            case '\'':
                decoded_string += '\'';
                break;
            case '"':
                decoded_string += '"';
                break;
            case 'b':
                decoded_string += '\b';
                break;
            case 'n':
                decoded_string += '\n';
                break;
            case 'r':
                decoded_string += '\r';
                break;
            case 't':
                decoded_string += '\t';
                break;
            case '\\':
                decoded_string += '\\';
                break;
            default:
                throw std::runtime_error("SqlUtil::Unescape: improperly encoded string! (ch == "
                                         + StringUtil::CStyleEscape(*ch) + ")");
            }
        }
    }

    return (*s = decoded_string);
}

tm DatetimeToTm(const std::string &datetime) {
    if (not IsValidDatetime(datetime))
        throw std::runtime_error("in SqlUtil::DatetimeToTm: invalid \"datetime\" argument \"" + datetime + "\"!");

    // current time format is YYYY-MM-DD hh:mm:ss
    tm time_struct;
    time_struct.tm_year  = std::atol(datetime.substr(0, 4).c_str()) - 1900;
    time_struct.tm_mon   = std::atol(datetime.substr(5, 2).c_str()) - 1;
    time_struct.tm_mday  = std::atol(datetime.substr(8, 2).c_str());
    time_struct.tm_hour  = std::atol(datetime.substr(11, 2).c_str());
    time_struct.tm_min   = std::atol(datetime.substr(14, 2).c_str());
    time_struct.tm_sec   = std::atol(datetime.substr(17, 2).c_str());
    time_struct.tm_isdst = -1; // Don't *ever* change this!!

    return time_struct;
}

time_t DatetimeToTimeT(const std::string &datetime) {
    tm time_struct(DatetimeToTm(datetime));
    errno = 0;
    const time_t ret_val(::mktime(&time_struct));
    if (unlikely(errno != 0))
        return TimeUtil::BAD_TIME_T;
    return ret_val;
}

std::string TmToDatetime(const struct tm &time_struct) {
    char sql_datetime[30 + 1];
    std::sprintf(sql_datetime, "%04u-%02u-%02u %02u:%02u:%02u", time_struct.tm_year + 1900,
                 time_struct.tm_mon + 1, time_struct.tm_mday, time_struct.tm_hour,
                 time_struct.tm_min, time_struct.tm_sec);

    return sql_datetime;
}

std::string TimeTToDatetime(const time_t time) {
    return TmToDatetime(*::gmtime(&time));
}

bool IsValidDatetime(const std::string &datetime) {
    if (datetime.length() == 10) {
        // Presumably "YYYY-MM-DD".

        unsigned year, month, day;
        if (std::sscanf(datetime.c_str(), "%4u-%2u-%2u", &year, &month, &day) != 3)
            return false;

        return (year >= 1000 and year <= 9999) and (month >= 1 and month <= 12) and
            (day >= 1 and day <= 365);
    } else if (datetime.length() == 19) {
        // Presumably "YYYY-MM-DD hh:mm:ss".

        unsigned year, month, day, hour, minute, second;
        if (std::sscanf(datetime.c_str(), "%4u-%2u-%2u %2u:%2u:%2u", &year, &month, &day, &hour,
                        &minute, &second) != 6)
            return false;

        return (year >= 1000 and year <= 9999) and (month >= 1 and month <= 12) and
            (day >= 1 and day <= 365) and hour <= 23 and minute <= 59 and second <= 61;
    } else
        return false;
}

std::string GetDatetime(const long offset) {
    time_t now(std::time(NULL) + offset);
    char buf[20 + 1];
    std::strftime(buf, sizeof(buf), "%F %T", std::localtime(&now));

    return buf;
}

std::set<std::string> GetColumnNames(DbConnection * const connection, const std::string &table_name) {
    const std::string SHOW_COUMNS_STMT("SHOW COLUMNS FROM `" + table_name + "`;");
    if (not connection->query(SHOW_COUMNS_STMT))
        throw std::runtime_error("in SqlUtil::GetColumnNames: Show columns failed: " + SHOW_COUMNS_STMT
                                 + " (" + connection->getLastErrorMessage() + ")");
    DbResultSet result_set(connection->getLastResultSet());
    std::set<std::string> column_names;
    while (const DbRow row = result_set.getNextRow())
        column_names.insert(row["Field"]);

    return column_names;
}

unsigned GetTableSize(DbConnection * const connection, const std::string &table_name) {
    connection->queryOrDie("SELECT COUNT(*) FROM " + table_name);
    DbResultSet result_set(connection->getLastResultSet());
    const DbRow first_row(result_set.getNextRow());

    return StringUtil::ToUnsigned(first_row[0]);
}

ThreadSafetyGuard::ThreadSafetyGuard(const ThreadType invoker_thread)
    : invoker_thread_(invoker_thread)
{
    switch (invoker_thread_) {
    case ThreadType::MAIN_THREAD:
        if (::mysql_library_init(0, nullptr, nullptr))
            LOG_ERROR("mysql_library_init failed");
        break;
    case ThreadType::WORKER_THREAD:
        if (::mysql_thread_init())
            LOG_ERROR("mysql_thread_init failed in worker thread " + std::to_string(::pthread_self()));
        break;
    default:
        LOG_ERROR("unknown invoker thread " + std::to_string(invoker_thread_));
    }
}

ThreadSafetyGuard::~ThreadSafetyGuard() {
    switch (invoker_thread_) {
    case ThreadType::MAIN_THREAD:
        ::mysql_library_end();
        break;
    case ThreadType::WORKER_THREAD:
        ::mysql_thread_end();
        break;
    default:
        LOG_ERROR("unknown invoker thread " + std::to_string(invoker_thread_));
    }
}

} // namespace SqlUtil
<|endoftext|>


<commit_before>#include <Halide.h>
using namespace Halide;

#include <iostream>

namespace Halide
{
	extern void testArray(Func f);
}

using namespace std;
int main(int argc, char **argv) {

    int width = 32;

    Func f("f"), g("g"), h("h"); Var x("x"), y("y");

    Uniform<int> offset("offset");
    offset = 666;

    Image<int> in(width+4);
    for (int i=0; i < in.width(); i++) in(i) = rand() / 2;

    h(x) = in(clamp(x, 0, in.width()));
    g(x) = h(x-1 + offset - *(int*)offset.data()) + h(x+1 + offset - *(int*)offset.data());
    f(x, y) = (g(x-1) + g(x+1)) + y;

    // Rehydrate ff by serializing then deserializing the pipeline out through f
    Func ff = rehydrate(f.serialize(), f.name());

    // reassign the uniform/image inputs
    ff.uniforms()[0].set(*(int*)offset.data());
    ff.uniformImages()[0] = in;

    vector<Func> funcs = f.funcs();
    set_union(funcs, f.transitiveFuncs());
    for (int i = 0; i < funcs.size(); i++) {
        funcs[i].root();
    }
    funcs = ff.funcs();
    set_union(funcs, ff.transitiveFuncs());
    for (int i = 0; i < funcs.size(); i++) {
        funcs[i].root();
    }

    if (use_gpu()) {
        f.cudaTile(x, y, 16, 16);
        ff.cudaTile(x, y, 16, 16);
    } else {
        Var xi("xi"), yi("yi");
        f.tile(x, y, xi, yi, 16, 16);
        ff.tile(x, y, xi, yi, 16, 16);
    }

    Image<int> out = ff.realize(width, width);
    Image<int> ref = f.realize(width, width);

    for (int y = 0; y < width; y++) {
        for (int x = 0; x < width; x++) {
            if (out(x, y) != ref(x, y)) {
                printf("out(%d, %d) = %d instead of %d\n", x, y, out(x, y), ref(x, y));
                return -1;
            }
        }
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Removed rehydrate test. Serialization will come later.<commit_after><|endoftext|>


<commit_before>/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#define BOOST_TEST_MODULE Timer

#include "main.cc"

#include <cap/timer.h>
#include <boost/test/unit_test.hpp>
#include <chrono>
#include <fstream>
#include <thread>

namespace cap
{
BOOST_AUTO_TEST_CASE(test_timer)
{
  unsigned int const tolerance = 10;
  Timer timer(boost::mpi::communicator(), "test");

  timer.start();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
  timer.stop();
  boost::chrono::process_cpu_clock::duration duration =
      timer.get_elapsed_time();
  boost::chrono::milliseconds ms =
      boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);
  BOOST_TEST(std::abs(ms.count() - 200) < tolerance);

  timer.start();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
  timer.stop();
  duration = timer.get_elapsed_time();
  ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);
  BOOST_TEST(std::abs(ms.count() - 400) < 2 * tolerance);

  timer.reset();
  timer.start();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
  timer.stop();
  duration = timer.get_elapsed_time();
  ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);
  BOOST_TEST(std::abs(ms.count() - 200) < tolerance);
}
}
<commit_msg>Relax tolerance in test_timer.<commit_after>/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#define BOOST_TEST_MODULE Timer

#include "main.cc"

#include <cap/timer.h>
#include <boost/test/unit_test.hpp>
#include <chrono>
#include <fstream>
#include <thread>

namespace cap
{
BOOST_AUTO_TEST_CASE(test_timer)
{
  unsigned int const tolerance = 15;
  Timer timer(boost::mpi::communicator(), "test");

  timer.start();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
  timer.stop();
  boost::chrono::process_cpu_clock::duration duration =
      timer.get_elapsed_time();
  boost::chrono::milliseconds ms =
      boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);
  BOOST_TEST(std::abs(ms.count() - 200) < tolerance);

  timer.start();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
  timer.stop();
  duration = timer.get_elapsed_time();
  ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);
  BOOST_TEST(std::abs(ms.count() - 400) < 2 * tolerance);

  timer.reset();
  timer.start();
  std::this_thread::sleep_for(std::chrono::milliseconds(200));
  timer.stop();
  duration = timer.get_elapsed_time();
  ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);
  BOOST_TEST(std::abs(ms.count() - 200) < tolerance);
}
}
<|endoftext|>


<commit_before>//
// Backtracking.
//
//  https://en.wikipedia.org/wiki/Backtracking
//  https://en.wikipedia.org/wiki/Call_stack
//  https://en.wikipedia.org/wiki/Recursion_(computer_science)
//  https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
//  https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
//
// "Backtracking" is a technique used to find a solution (e.g. a password) when
// validity constraints are known (e.g. the password can contain at most three
// decimal digits).
//
// The constraints will be used to reject sets of invalid candidates, thereby
// speeding up the search process; the algorithm will skip generating candidates
// which are known to not satisfy the constraints.
//
// In contrast, a brute search algorithm will generate all possible candidates.
// (A backtracking algorithm which never rejects any candidates becomes a brute
// force algorithm.)
//
// Backtracking algorithms are often implemented using recursion. This is done
// because it simplifies the code in languages such as C, whereby the programmer
// uses a (call) stack "for free" to hold the algorithm's state, i.e. the old
// candidates to which the algorithm needs to "backtrack" in order to generate
// their children candidates.
//
// -----------------------------------------------------------------------------
//
// The basic C-style pseudocode for recursive backtracking is:
//
//  ///
//  /// @brief Performs recursive backtracking.
//  /// @param [in] c               Current candidate to be checked.
//  ///
//  void backtrack(candidate c)
//  {
//      //
//      // c isn't a solution, and its children cannot
//      // become solutions either, so go no further
//      //
//      if (reject(c))
//          return;
//
//      //
//      // c is a solution!
//      //
//      if (accept(c))
//          /* use, save, print, etc. */ ;
//
//      //
//      // does c have a child? i.e. "001" -> "001a"
//      // if not, c_child gets LINEAGE_IS_OVER
//      //
//      // (in practice "LINEAGE_IS_OVER" can be any special value,
//      // such as NULL, that is interpreted as the lack of a child)
//      //
//      candidate c_child = first_child(c);
//
//      while (c_child != LINEAGE_IS_OVER)
//      {
//          //
//          // verify the child candidate, and its children, and so on...
//          //
//          backtrack(c_child);
//
//          //
//          // does c_child have a sibling? i.e. "001a" -> "001b"
//          // if not, c_child gets LINEAGE_IS_OVER
//          //
//          c_child = next_child(c_child);
//      }
//  }
//
// -----------------------------------------------------------------------------
//
// The basic C-style pseudocode for non-recursive backtracking is:
//
//  ///
//  /// @brief Performs non-recursive backtracking.
//  /// @param [in] start           Beginning candidate, to start with.
//  ///
//  void backtrack(candidate start)
//  {
//      //
//      // because recursion isn't used anymore, we do not get a Call Stack
//      // in which to hold our current state "for free" so we must "manually"
//      // use a Stack container, that implements the following operations:
//      //
//      //  void        stack::push(candidate)  // adds a new "c" to the top
//      //  void        stack::pop()            // removes the current top
//      //  candidate   stack::top()            // returns the current top
//      //  bool        stack::empty()          // returns if the stack is empty
//      //
//      // note that the container isn't strictly required to be a Stack;
//      // for instance it could be a Queue but then the algorithm will need
//      // to be fine-tuned accordingly to the way a Queue works
//      //
//      stack<candidate> stk;
//
//      stk.push(start);
//
//      while (!stk.empty())
//      {
//          if (reject(stk.top()))
//          {
//              stk.pop();
//              continue;
//          }
//
//          if (accept(stk.top()))
//              /* use, save, print, etc. */ ;
//
//          candidate child = first_child(stk.top());
//
//          stk.pop();
//
//          if (child != LINEAGE_IS_OVER)
//          {
//              stk.push(child);
//
//              candidate sibling = next_child(stk.top());
//
//              while (sibling != LINEAGE_IS_OVER)
//              {
//                  stk.push(sibling);
//                  sibling = next_child(stk.top());
//              }
//          }
//      }
//  }
//
// -----------------------------------------------------------------------------
//
// The following program will use backtracking to find all passwords with the
// following example constraints:
//
//  (1) only lowercase latin letters (a-z) and decimal digits (0-9) are allowed
//  (2) there must be at least two digits in a password
//  (3) there must be at least one letter 'b' in a password
//  (4) the minimum length of a password is 3
//  (5) the maximum length of a password is 5
//
// The program implements:
//
//  (a) traditional recursive backtrack:        backtrack_rec()
//  (b) stack-based non-recursive backtrack:    backtrack_stk()
//

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <locale>
#include <new>
#include <stack>
#include <stdexcept>
#include <string>

namespace
{

///
/// @brief Returns whether a candidate and its children should be rejected.
/// @details Rejection occurs if the candidate:
///  (1) contains characters which aren't either lowercase latin letter (a-z)
///      or decimal digit (0-9), such as 'A' or '?', OR
///  (2) is at least of length 5 yet it doesn't contain at least two digits, OR
///  (3) is at least of length 5 yet it doesn't contain at least one letter 'b'
/// @note The function `first_child()` shall not generate candidate strings
///  of length greater than 5.
/// @param [in] c                   Candidate to be verified.
/// @returns Whether or not rejection has occurred.
/// @retval true                    The candidate was rejected.
/// @retval false                   The candidate was not rejected.
///
bool reject(const std::string &c)
try
{
    for (char ch: c)
    {
        if (!std::islower(ch, std::locale()) &&
            !std::isdigit(ch, std::locale()))
        {
            return true;
        }
    }

    if (c.length() >= 5)
    {
        if (std::count(c.begin(), c.end(), 'b') < 1 ||
            std::count_if(c.begin(), c.end(),
                [](const char &ch) -> bool
                {
                    return std::isdigit(ch, std::locale());
                }) < 2)
        {
            return true;
        }
    }

    return false;
}
catch (const std::bad_alloc &e)
{
    std::cerr << "`std::bad_alloc` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (const std::runtime_error &e)
{
    std::cerr << "`std::runtime_error` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Returns if a candidate is accepted as a solution.
/// @details Acceptance occurs if the candidate:
///  (0) wasn't rejected previously (this is a precondition), AND
///  (1) has minimum length 3, AND
///  (2) has maximum length 5, AND
///  (3) contains at least two digits, AND
///  (4) contains at least one letter 'b'
/// @pre `reject(c) == false`
/// @param [in] c                   Candidate to be verified.
/// @returns Whether or not acception has occurred.
/// @retval true                    The candidate was accepted.
/// @retval false                   The candidate was not accepted.
///
bool accept(const std::string &c)
try
{
    assert(reject(c) == false);

    if (c.length() >= 3 &&
        c.length() <= 5 &&
        std::count(c.begin(), c.end(), 'b') >= 1 &&
        std::count_if(c.begin(), c.end(),
            [](const char &ch) -> bool
            {
                return std::isdigit(ch, std::locale());
            }) >= 2)
    {
        return true;
    }

    return false;
}
catch (const std::bad_alloc &e)
{
    std::cerr << "`std::bad_alloc` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (const std::runtime_error &e)
{
    std::cerr << "`std::runtime_error` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief The set of valid characters to be used in a new candidate.
/// @details This global serves to "specialize" the candidate child and sibling
///  generation functions `first_child()` and `next_child()`.
///
const std::string valid_chars("abcdefghijklmnopqrstuvwxyz0123456789");

///
/// @brief Retrieves the first child of the candidate.
/// @details The child is returned as a pointer but must be dereferenced and
///  stored as a string as soon as it's retrieved, if not null.
/// @todo Use `std::optional` from C++17 in the future?
/// @pre `valid_chars.empty() == false`
/// @param [in] c                   Candidate for which to get the child.
/// @returns Pointer to the child.
/// @retval nullptr                 If there are no children.
///
const std::string * first_child(const std::string &c)
try
{
    assert(valid_chars.empty() == false);

    static std::string child;

    if (c.length() == 5)
        return nullptr;

    child = c + valid_chars.front();
    return &child;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Retrieves the next sibling of the candidate.
/// @details The sibling is returned as a pointer but must be dereferenced and
///  stored as a string as soon as it's retrieved, if not null.
/// @todo Use `std::optional` from C++17 in the future?
/// @pre `valid_chars.empty() == false`
/// @pre `c.empty() == false`
/// @param [in] c                   Candidate for which to get the sibling.
/// @returns Pointer to the sibling.
/// @retval nullptr                 If there are no siblings.
///
const std::string * next_child(const std::string &c)
try
{
    assert(valid_chars.empty() == false);
    assert(c.empty() == false);

    static std::string sibling;

    if (c.back() == valid_chars.back())
        return nullptr;

    sibling = c;
    sibling.back() = valid_chars.at(valid_chars.find(c.back()) + 1);
    return &sibling;
}
catch (const std::out_of_range &e)
{
    std::cerr << "`std::out_of_range` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Performs recursive backtracking.
/// @param [in] c                   Current candidate to be checked.
///
void backtrack_rec(const std::string &c)
try
{
    if (reject(c))
        return;

    if (accept(c))
        std::cout << c << '\n';

    const std::string *p_child(first_child(c));

    while (p_child != nullptr)
    {
        const std::string c_child(*p_child);

        backtrack_rec(c_child);
        p_child = next_child(c_child);
    }
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Performs non-recursive backtracking, using a Stack.
/// @param [in] start               Beginning candidate, to start with.
///
void backtrack_stk(const std::string &start)
try
{
    std::stack<std::string> stk;

    stk.push(start);

    while (!stk.empty())
    {
        if (reject(stk.top()))
        {
            stk.pop();
            continue;
        }

        if (accept(stk.top()))
            std::cout << stk.top() << '\n';

        const std::string *p_child(first_child(stk.top()));

        stk.pop();

        if (p_child != nullptr)
        {
            stk.push(*p_child);

            const std::string *p_sibling(next_child(stk.top()));

            while (p_sibling != nullptr)
            {
                stk.push(*p_sibling);
                p_sibling = next_child(stk.top());
            }
        }
    }
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

} // unnamed namespace

///
/// @brief Enters the program.
/// @returns Whether or not the operation was successful.
/// @retval EXIT_SUCCESS            Operation success.
/// @retval EXIT_FAILURE            Operation failure.
///
int main()
try
{
//  backtrack_rec("");
    backtrack_stk("");
    return EXIT_SUCCESS;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    return EXIT_FAILURE;
}
<commit_msg>Update backtrack.cpp<commit_after>//
// Backtracking.
//
//  https://en.wikipedia.org/wiki/Backtracking
//  https://en.wikipedia.org/wiki/Call_stack
//  https://en.wikipedia.org/wiki/Recursion_(computer_science)
//  https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
//  https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
//
// "Backtracking" is a technique used to find a solution (e.g. a password) when
// validity constraints are known (e.g. the password can contain at most three
// decimal digits).
//
// The constraints will be used to reject sets of invalid candidates, thereby
// speeding up the search process; the algorithm will skip generating candidates
// which are known to not satisfy the constraints.
//
// In contrast, a brute search algorithm will generate all possible candidates.
// (A backtracking algorithm which never rejects any candidates becomes a brute
// force algorithm.)
//
// Backtracking algorithms are often implemented using recursion. This is done
// because it simplifies the code in languages such as C, whereby the programmer
// uses a (call) stack "for free" to hold the algorithm's state, i.e. the old
// candidates to which the algorithm needs to "backtrack" in order to generate
// their children candidates.
//
// -----------------------------------------------------------------------------
//
// The basic C-style pseudocode for recursive backtracking is:
//
//  ///
//  /// @brief Performs recursive backtracking.
//  /// @param [in] c               Current candidate to be checked.
//  ///
//  void backtrack(candidate c)
//  {
//      //
//      // c isn't a solution, and its children cannot
//      // become solutions either, so go no further
//      //
//      if (reject(c))
//          return;
//
//      //
//      // c is a solution!
//      //
//      if (accept(c))
//          /* use, save, print, etc. */ ;
//
//      //
//      // does c have a child? i.e. "001" -> "001a"
//      // if not, c_child gets LINEAGE_IS_OVER
//      //
//      // (in practice "LINEAGE_IS_OVER" can be any special value,
//      // such as NULL, that is interpreted as the lack of a child)
//      //
//      candidate c_child = first_child(c);
//
//      while (c_child != LINEAGE_IS_OVER)
//      {
//          //
//          // verify the child candidate, and its children, and so on...
//          //
//          backtrack(c_child);
//
//          //
//          // does c_child have a sibling? i.e. "001a" -> "001b"
//          // if not, c_child gets LINEAGE_IS_OVER
//          //
//          c_child = next_child(c_child);
//      }
//  }
//
// -----------------------------------------------------------------------------
//
// The basic C-style pseudocode for non-recursive backtracking is:
//
//  ///
//  /// @brief Performs non-recursive backtracking.
//  /// @param [in] start           Beginning candidate, to start with.
//  ///
//  void backtrack(candidate start)
//  {
//      //
//      // because recursion isn't used anymore, we do not get a Call Stack
//      // in which to hold our current state "for free" so we must "manually"
//      // use a Stack container, that implements the following operations:
//      //
//      //  void        stack::push(candidate)  // adds a new "c" to the top
//      //  void        stack::pop()            // removes the current top
//      //  candidate   stack::top()            // returns the current top
//      //  bool        stack::empty()          // returns if the stack is empty
//      //
//      // note that the container isn't strictly required to be a Stack;
//      // for instance it could be a Queue but then the algorithm will need
//      // to be fine-tuned accordingly to the way a Queue works
//      //
//      stack<candidate> stk;
//
//      stk.push(start);
//
//      while (!stk.empty())
//      {
//          if (reject(stk.top()))
//          {
//              stk.pop();
//              continue;
//          }
//
//          if (accept(stk.top()))
//              /* use, save, print, etc. */ ;
//
//          candidate child = first_child(stk.top());
//
//          stk.pop();
//
//          if (child != LINEAGE_IS_OVER)
//          {
//              stk.push(child);
//
//              candidate sibling = next_child(stk.top());
//
//              while (sibling != LINEAGE_IS_OVER)
//              {
//                  stk.push(sibling);
//                  sibling = next_child(stk.top());
//              }
//          }
//      }
//  }
//
// -----------------------------------------------------------------------------
//
// The following program will use backtracking to find all passwords with the
// following example constraints:
//
//  (1) only lowercase latin letters (a-z) and decimal digits (0-9) are allowed
//  (2) there must be at least two digits in a password
//  (3) there must be at least one letter 'b' in a password
//  (4) the minimum length of a password is 3
//  (5) the maximum length of a password is 5
//
// The program implements:
//
//  (a) traditional recursive backtrack:        backtrack_rec()
//  (b) stack-based non-recursive backtrack:    backtrack_stk()
//

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <locale>
#include <new>
#include <stack>
#include <stdexcept>
#include <string>

namespace
{

///
/// @brief Returns whether a candidate and its children should be rejected.
/// @details Rejection occurs if the candidate:
///  (1) contains characters which aren't either lowercase latin letter (a-z)
///      or decimal digit (0-9), such as 'A' or '?', OR
///  (2) is at least of length 5 yet it doesn't contain at least two digits, OR
///  (3) is at least of length 5 yet it doesn't contain at least one letter 'b'
/// @note The function `first_child()` shall not generate candidate strings
///  of length greater than 5.
/// @param [in] c                   Candidate to be verified.
/// @returns Whether or not rejection has occurred.
/// @retval true                    The candidate was rejected.
/// @retval false                   The candidate was not rejected.
///
bool reject(const std::string &c)
try
{
    for (char ch: c)
    {
        if (!std::islower(ch, std::locale()) &&
            !std::isdigit(ch, std::locale()))
        {
            return true;
        }
    }

    if (c.length() >= 5)
    {
        if (std::count(c.begin(), c.end(), 'b') < 1 ||
            std::count_if(c.begin(), c.end(),
                [](const char &ch) -> bool
                {
                    return std::isdigit(ch, std::locale());
                }) < 2)
        {
            return true;
        }
    }

    return false;
}
catch (const std::bad_alloc &e)
{
    std::cerr << "`std::bad_alloc` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (const std::runtime_error &e)
{
    std::cerr << "`std::runtime_error` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Returns if a candidate is accepted as a solution.
/// @details Acceptance occurs if the candidate:
///  (0) wasn't rejected previously (this is a precondition), AND
///  (1) has minimum length 3, AND
///  (2) has maximum length 5, AND
///  (3) contains at least two digits, AND
///  (4) contains at least one letter 'b'
/// @pre `reject(c) == false`
/// @param [in] c                   Candidate to be verified.
/// @returns Whether or not acception has occurred.
/// @retval true                    The candidate was accepted.
/// @retval false                   The candidate was not accepted.
///
bool accept(const std::string &c)
try
{
    assert(reject(c) == false);

    if (c.length() >= 3 &&
        c.length() <= 5 &&
        std::count(c.begin(), c.end(), 'b') >= 1 &&
        std::count_if(c.begin(), c.end(),
            [](const char &ch) -> bool
            {
                return std::isdigit(ch, std::locale());
            }) >= 2)
    {
        return true;
    }

    return false;
}
catch (const std::bad_alloc &e)
{
    std::cerr << "`std::bad_alloc` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (const std::runtime_error &e)
{
    std::cerr << "`std::runtime_error` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief The set of valid characters to be used in a new candidate.
/// @details This global serves to "specialize" the candidate child and sibling
///  generation functions `first_child()` and `next_child()`.
///
const std::string valid_chars("abcdefghijklmnopqrstuvwxyz0123456789");

///
/// @brief Retrieves the first child of the candidate.
/// @details The child is returned as a pointer but must be dereferenced and
///  stored as a string as soon as it's retrieved, if not null.
/// @todo Use `std::optional` from C++17 in the future?
/// @pre `valid_chars.empty() == false`
/// @param [in] c                   Candidate for which to get the child.
/// @returns Pointer to the child.
/// @retval nullptr                 If there are no children.
///
const std::string * first_child(const std::string &c)
try
{
    assert(valid_chars.empty() == false);

    static std::string child;

    if (c.length() >= 5)
        return nullptr;

    child = c + valid_chars.front();
    return &child;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Retrieves the next sibling of the candidate.
/// @details The sibling is returned as a pointer but must be dereferenced and
///  stored as a string as soon as it's retrieved, if not null.
/// @todo Use `std::optional` from C++17 in the future?
/// @pre `valid_chars.empty() == false`
/// @pre `c.empty() == false`
/// @param [in] c                   Candidate for which to get the sibling.
/// @returns Pointer to the sibling.
/// @retval nullptr                 If there are no siblings.
///
const std::string * next_child(const std::string &c)
try
{
    assert(valid_chars.empty() == false);
    assert(c.empty() == false);

    static std::string sibling;

    if (c.back() == valid_chars.back())
        return nullptr;

    sibling = c;
    sibling.back() = valid_chars.at(valid_chars.find(c.back()) + 1);
    return &sibling;
}
catch (const std::out_of_range &e)
{
    std::cerr << "`std::out_of_range` exception in `" << __func__ << "`: ";
    std::cerr << e.what() << std::endl;
    throw;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Performs recursive backtracking.
/// @param [in] c                   Current candidate to be checked.
///
void backtrack_rec(const std::string &c)
try
{
    if (reject(c))
        return;

    if (accept(c))
        std::cout << c << '\n';

    const std::string *p_child(first_child(c));

    while (p_child != nullptr)
    {
        const std::string c_child(*p_child);

        backtrack_rec(c_child);
        p_child = next_child(c_child);
    }
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

///
/// @brief Performs non-recursive backtracking, using a Stack.
/// @param [in] start               Beginning candidate, to start with.
///
void backtrack_stk(const std::string &start)
try
{
    std::stack<std::string> stk;

    stk.push(start);

    while (!stk.empty())
    {
        if (reject(stk.top()))
        {
            stk.pop();
            continue;
        }

        if (accept(stk.top()))
            std::cout << stk.top() << '\n';

        const std::string *p_child(first_child(stk.top()));

        stk.pop();

        if (p_child != nullptr)
        {
            stk.push(*p_child);

            const std::string *p_sibling(next_child(stk.top()));

            while (p_sibling != nullptr)
            {
                stk.push(*p_sibling);
                p_sibling = next_child(stk.top());
            }
        }
    }
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    throw;
}

} // unnamed namespace

///
/// @brief Enters the program.
/// @returns Whether or not the operation was successful.
/// @retval EXIT_SUCCESS            Operation success.
/// @retval EXIT_FAILURE            Operation failure.
///
int main()
try
{
//  backtrack_rec("");
    backtrack_stk("");
    return EXIT_SUCCESS;
}
catch (...)
{
    std::cerr << "unknown exception in `" << __func__ << '`' << std::endl;
    return EXIT_FAILURE;
}
<|endoftext|>