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

//-------------------------------------------------------------------------
//               Implementation of the cascade vertexer class
//          Reads V0s and tracks, writes out cascade vertices
//                     Fills the ESD with the cascades
//    Origin: Christian Kuhn, IReS, Strasbourg, christian.kuhn@ires.in2p3.fr
//-------------------------------------------------------------------------

//modified by R. Vernet 30/6/2006 : daughter label
//modified by R. Vernet  3/7/2006 : causality
//modified by I. Belikov 24/11/2006 : static setter for the default cuts

#include "TRandom3.h"
#include "AliESDEvent.h"
#include "AliESDcascade.h"
#include "AliCascadeVertexerUncheckedCharges.h"

ClassImp(AliCascadeVertexerUncheckedCharges)

//A set of loose cuts
Double_t
AliCascadeVertexerUncheckedCharges::fgChi2max=33.;   //maximal allowed chi2
Double_t
AliCascadeVertexerUncheckedCharges::fgDV0min=0.01;   //min V0 impact parameter
Double_t
AliCascadeVertexerUncheckedCharges::fgMassWin=0.008; //"window" around the Lambda mass
Double_t
AliCascadeVertexerUncheckedCharges::fgDBachMin=0.01; //min bachelor impact parameter
Double_t
AliCascadeVertexerUncheckedCharges::fgDCAmax=2.0;    //max DCA between the V0 and the track
Double_t
AliCascadeVertexerUncheckedCharges::fgCPAmin=0.98; //min cosine of the cascade pointing angle
Double_t
AliCascadeVertexerUncheckedCharges::fgRmin=0.2;      //min radius of the fiducial volume
Double_t
AliCascadeVertexerUncheckedCharges::fgRmax=100.;     //max radius of the fiducial volume

Double_t AliCascadeVertexerUncheckedCharges::fgMaxEta=0.8;        //max |eta|
Int_t AliCascadeVertexerUncheckedCharges::fgMinClusters=70;   //min clusters (>=)
Bool_t AliCascadeVertexerUncheckedCharges::fgSwitchCharges=kFALSE;   //
Bool_t AliCascadeVertexerUncheckedCharges::fgUseOnTheFlyV0=kFALSE;   //HIGHLY EXPERIMENTAL

Int_t AliCascadeVertexerUncheckedCharges::V0sTracks2CascadeVertices(AliESDEvent *event) {
    //--------------------------------------------------------------------
    // This function reconstructs cascade vertices
    //      Adapted to the ESD by I.Belikov (Jouri.Belikov@cern.ch)
    //--------------------------------------------------------------------
    const AliESDVertex *vtxT3D=event->GetPrimaryVertex();

    Double_t xPrimaryVertex=vtxT3D->GetX();
    Double_t yPrimaryVertex=vtxT3D->GetY();
    Double_t zPrimaryVertex=vtxT3D->GetZ();

    Double_t b=event->GetMagneticField();
    Int_t nV0=(Int_t)event->GetNumberOfV0s();

    TRandom3 lPRNG;
    lPRNG.SetSeed(0);

    //stores relevant V0s in an array
    TObjArray vtcs(nV0);
    Int_t i;
    for (i=0; i<nV0; i++) {
        AliESDv0 *v=event->GetV0(i);
        if ( v->GetOnFlyStatus() && !fUseOnTheFlyV0) continue;
        if (!v->GetOnFlyStatus() &&  fUseOnTheFlyV0) continue;

        //Fix incorrect storing of charges in on-the-fly V0s
        if( fUseOnTheFlyV0 ){
            //Fix charge ordering
            CheckChargeV0( v );
            //Remove like-sign
            if( v->GetParamN()->Charge() > 0 && v->GetParamP()->Charge() > 0 ) continue;
            if( v->GetParamN()->Charge() < 0 && v->GetParamP()->Charge() < 0 ) continue;
        }

        if (v->GetD(xPrimaryVertex,yPrimaryVertex,zPrimaryVertex)<fDV0min) continue;
        vtcs.AddLast(v);
    }
    nV0=vtcs.GetEntriesFast();

    // stores relevant tracks in another array
    Int_t nentr=(Int_t)event->GetNumberOfTracks();
    TArrayI trk(nentr); Int_t ntr=0;
    for (i=0; i<nentr; i++) {
        AliESDtrack *esdtr=event->GetTrack(i);

        ULong_t status=esdtr->GetStatus();

        if ((status&AliESDtrack::kITSrefit)==0)
            if ((status&AliESDtrack::kTPCrefit)==0) continue;

        //Track pre-selection: clusters
        if (esdtr->GetTPCNcls() < fMinClusters ) continue;

        if (TMath::Abs(esdtr->GetD(xPrimaryVertex,yPrimaryVertex,b))<fDBachMin) continue;

        trk[ntr++]=i;
    }

    Double_t massLambda=1.11568;
    Int_t ncasc=0;

    // Looking for both cascades and anti-cascades simultaneously

    for (i=0; i<nV0; i++) { //loop on V0s

        AliESDv0 *v=(AliESDv0*)vtcs.UncheckedAt(i);
        AliESDv0 v0(*v);

        Float_t lMassAsLambda     = 0;
        Float_t lMassAsAntiLambda = 0;

        v0.ChangeMassHypothesis(kLambda0); // the v0 must be Lambda
        lMassAsLambda = v0.GetEffMass();

        v0.ChangeMassHypothesis(kLambda0Bar); // the v0 must be Lambda
        lMassAsAntiLambda = v0.GetEffMass();

        //Only disregard if it does not pass any of the desired hypotheses
        if (TMath::Abs(lMassAsLambda-massLambda)>fMassWin &&
            TMath::Abs(lMassAsAntiLambda-massLambda)>fMassWin) continue;

        for (Int_t j=0; j<ntr; j++) {//loop on tracks
            Int_t bidx=trk[j];
            //Check if different tracks are used all times
            if (bidx==v0.GetIndex(0)) continue; //Bo:  consistency 0 for neg
            if (bidx==v0.GetIndex(1)) continue; //Bo:  consistency 0 for neg
            if (v0.GetIndex(0)==v0.GetIndex(1)) continue; //Bo:  consistency 0 for neg

            AliESDtrack *btrk=event->GetTrack(bidx);

            //Do not check charges!
            AliESDv0 *pv0=&v0;
            AliExternalTrackParam bt(*btrk), *pbt=&bt;

            Double_t dca=PropagateToDCA(pv0,pbt,b);
            if (dca > fDCAmax) continue;

            //eta cut - test
            if (TMath::Abs(pbt->Eta())>fMaxEta) continue;

            AliESDcascade cascade(*pv0,*pbt,bidx);//constucts a cascade candidate

            Double_t x,y,z; cascade.GetXYZcascade(x,y,z); // Bo: bug correction
            Double_t r2=x*x + y*y;
            if (r2 > fRmax*fRmax) continue;   // condition on fiducial zone
            if (r2 < fRmin*fRmin) continue;

            Double_t pxV0,pyV0,pzV0;
            pv0->GetPxPyPz(pxV0,pyV0,pzV0);
            if (x*pxV0+y*pyV0+z*pzV0 < 0) continue; //causality

            Double_t x1,y1,z1; pv0->GetXYZ(x1,y1,z1);
            if (r2 > (x1*x1+y1*y1)) continue;

            if (cascade.GetCascadeCosineOfPointingAngle(xPrimaryVertex,yPrimaryVertex,zPrimaryVertex) <fCPAmin) continue; //condition on the cascade pointing angle

            cascade.SetDcaXiDaughters(dca);
            event->AddCascade(&cascade);
            ncasc++;
        } // end loop tracks
    } // end loop V0s

    Info("V0sTracks2CascadeVertices","Number of reconstructed cascades: %d",ncasc);

    return 0;
}

Double_t AliCascadeVertexerUncheckedCharges::Det(Double_t a00, Double_t a01, Double_t a10, Double_t a11) const {
    //--------------------------------------------------------------------
    // This function calculates locally a 2x2 determinant
    //--------------------------------------------------------------------
    return a00*a11 - a01*a10;
}

Double_t AliCascadeVertexerUncheckedCharges::Det(Double_t a00,Double_t a01,Double_t a02,
                                      Double_t a10,Double_t a11,Double_t a12,
                                      Double_t a20,Double_t a21,Double_t a22) const {
    //--------------------------------------------------------------------
    // This function calculates locally a 3x3 determinant
    //--------------------------------------------------------------------
    return  a00*Det(a11,a12,a21,a22)-a01*Det(a10,a12,a20,a22)+a02*Det(a10,a11,a20,a21);
}

Double_t AliCascadeVertexerUncheckedCharges::PropagateToDCA(AliESDv0 *v, AliExternalTrackParam *t, Double_t b) {
    //--------------------------------------------------------------------
    // This function returns the DCA between the V0 and the track
    //--------------------------------------------------------------------
    Double_t alpha=t->GetAlpha(), cs1=TMath::Cos(alpha), sn1=TMath::Sin(alpha);
    Double_t r[3]; t->GetXYZ(r);
    Double_t x1=r[0], y1=r[1], z1=r[2];
    Double_t p[3]; t->GetPxPyPz(p);
    Double_t px1=p[0], py1=p[1], pz1=p[2];

    Double_t x2,y2,z2;     // position and momentum of V0
    Double_t px2,py2,pz2;

    v->GetXYZ(x2,y2,z2);
    v->GetPxPyPz(px2,py2,pz2);

    // calculation dca

    Double_t dd= Det(x2-x1,y2-y1,z2-z1,px1,py1,pz1,px2,py2,pz2);
    Double_t ax= Det(py1,pz1,py2,pz2);
    Double_t ay=-Det(px1,pz1,px2,pz2);
    Double_t az= Det(px1,py1,px2,py2);

    Double_t dca=TMath::Abs(dd)/TMath::Sqrt(ax*ax + ay*ay + az*az);

    //points of the DCA
    Double_t t1 = Det(x2-x1,y2-y1,z2-z1,px2,py2,pz2,ax,ay,az)/
    Det(px1,py1,pz1,px2,py2,pz2,ax,ay,az);

    x1 += px1*t1; y1 += py1*t1; //z1 += pz1*t1;

    //propagate track to the points of DCA

    x1=x1*cs1 + y1*sn1;
    if (!t->PropagateTo(x1,b)) {
        Error("PropagateToDCA","Propagation failed !");
        return 1.e+33;
    }

    return dca;
}

//________________________________________________________________________
void AliCascadeVertexerUncheckedCharges::CheckChargeV0(AliESDv0 *v0)
{
    // This function checks charge of negative and positive daughter tracks.
    // If incorrectly defined (onfly vertexer), swaps out.
    if( v0->GetParamN()->Charge() > 0 && v0->GetParamP()->Charge() < 0 ) {
        //V0 daughter track swapping is required! Note: everything is swapped here... P->N, N->P
        Long_t lCorrectNidx = v0->GetPindex();
        Long_t lCorrectPidx = v0->GetNindex();
        Double32_t	lCorrectNmom[3];
        Double32_t	lCorrectPmom[3];
        v0->GetPPxPyPz( lCorrectNmom[0], lCorrectNmom[1], lCorrectNmom[2] );
        v0->GetNPxPyPz( lCorrectPmom[0], lCorrectPmom[1], lCorrectPmom[2] );

        AliExternalTrackParam	lCorrectParamN(
                                               v0->GetParamP()->GetX() ,
                                               v0->GetParamP()->GetAlpha() ,
                                               v0->GetParamP()->GetParameter() ,
                                               v0->GetParamP()->GetCovariance()
                                               );
        AliExternalTrackParam	lCorrectParamP(
                                               v0->GetParamN()->GetX() ,
                                               v0->GetParamN()->GetAlpha() ,
                                               v0->GetParamN()->GetParameter() ,
                                               v0->GetParamN()->GetCovariance()
                                               );
        lCorrectParamN.SetMostProbablePt( v0->GetParamP()->GetMostProbablePt() );
        lCorrectParamP.SetMostProbablePt( v0->GetParamN()->GetMostProbablePt() );

        //Get Variables___________________________________________________
        Double_t lDcaV0Daughters = v0 -> GetDcaV0Daughters();
        Double_t lCosPALocal     = v0 -> GetV0CosineOfPointingAngle();
        Bool_t lOnFlyStatusLocal = v0 -> GetOnFlyStatus();

        //Create Replacement Object_______________________________________
        AliESDv0 *v0correct = new AliESDv0(lCorrectParamN,lCorrectNidx,lCorrectParamP,lCorrectPidx);
        v0correct->SetDcaV0Daughters          ( lDcaV0Daughters   );
        v0correct->SetV0CosineOfPointingAngle ( lCosPALocal       );
        v0correct->ChangeMassHypothesis       ( kK0Short          );
        v0correct->SetOnFlyStatus             ( lOnFlyStatusLocal );

        //Reverse Cluster info..._________________________________________
        v0correct->SetClusters( v0->GetClusters( 1 ), v0->GetClusters ( 0 ) );

        *v0 = *v0correct;
        //Proper cleanup..._______________________________________________
        v0correct->Delete();
        v0correct = 0x0;

        //Just another cross-check and output_____________________________
        if( v0->GetParamN()->Charge() > 0 && v0->GetParamP()->Charge() < 0 ) {
            AliWarning("Found Swapped Charges, tried to correct but something FAILED!");
        } else {
            //AliWarning("Found Swapped Charges and fixed.");
        }
        //________________________________________________________________
    } else {
        //Don't touch it! ---
        //Printf("Ah, nice. Charges are already ordered...");
    }
    return;
}

<commit_msg>Revert to no checking of charges in unchecked charge version of vertexer<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.                  *
 **************************************************************************/

//-------------------------------------------------------------------------
//               Implementation of the cascade vertexer class
//          Reads V0s and tracks, writes out cascade vertices
//                     Fills the ESD with the cascades
//    Origin: Christian Kuhn, IReS, Strasbourg, christian.kuhn@ires.in2p3.fr
//-------------------------------------------------------------------------

//modified by R. Vernet 30/6/2006 : daughter label
//modified by R. Vernet  3/7/2006 : causality
//modified by I. Belikov 24/11/2006 : static setter for the default cuts

#include "TRandom3.h"
#include "AliESDEvent.h"
#include "AliESDcascade.h"
#include "AliCascadeVertexerUncheckedCharges.h"

ClassImp(AliCascadeVertexerUncheckedCharges)

//A set of loose cuts
Double_t
AliCascadeVertexerUncheckedCharges::fgChi2max=33.;   //maximal allowed chi2
Double_t
AliCascadeVertexerUncheckedCharges::fgDV0min=0.01;   //min V0 impact parameter
Double_t
AliCascadeVertexerUncheckedCharges::fgMassWin=0.008; //"window" around the Lambda mass
Double_t
AliCascadeVertexerUncheckedCharges::fgDBachMin=0.01; //min bachelor impact parameter
Double_t
AliCascadeVertexerUncheckedCharges::fgDCAmax=2.0;    //max DCA between the V0 and the track
Double_t
AliCascadeVertexerUncheckedCharges::fgCPAmin=0.98; //min cosine of the cascade pointing angle
Double_t
AliCascadeVertexerUncheckedCharges::fgRmin=0.2;      //min radius of the fiducial volume
Double_t
AliCascadeVertexerUncheckedCharges::fgRmax=100.;     //max radius of the fiducial volume

Double_t AliCascadeVertexerUncheckedCharges::fgMaxEta=0.8;        //max |eta|
Int_t AliCascadeVertexerUncheckedCharges::fgMinClusters=70;   //min clusters (>=)
Bool_t AliCascadeVertexerUncheckedCharges::fgSwitchCharges=kFALSE;   //
Bool_t AliCascadeVertexerUncheckedCharges::fgUseOnTheFlyV0=kFALSE;   //HIGHLY EXPERIMENTAL

Int_t AliCascadeVertexerUncheckedCharges::V0sTracks2CascadeVertices(AliESDEvent *event) {
    //--------------------------------------------------------------------
    // This function reconstructs cascade vertices
    //      Adapted to the ESD by I.Belikov (Jouri.Belikov@cern.ch)
    //--------------------------------------------------------------------
    const AliESDVertex *vtxT3D=event->GetPrimaryVertex();

    Double_t xPrimaryVertex=vtxT3D->GetX();
    Double_t yPrimaryVertex=vtxT3D->GetY();
    Double_t zPrimaryVertex=vtxT3D->GetZ();

    Double_t b=event->GetMagneticField();
    Int_t nV0=(Int_t)event->GetNumberOfV0s();

    TRandom3 lPRNG;
    lPRNG.SetSeed(0);

    //stores relevant V0s in an array
    TObjArray vtcs(nV0);
    Int_t i;
    for (i=0; i<nV0; i++) {
        AliESDv0 *v=event->GetV0(i);
        if ( v->GetOnFlyStatus() && !fUseOnTheFlyV0) continue;
        if (!v->GetOnFlyStatus() &&  fUseOnTheFlyV0) continue;

        //Fix incorrect storing of charges in on-the-fly V0s
        if( fUseOnTheFlyV0 ){
            //Fix charge ordering
            CheckChargeV0( v );
            //Remove like-sign --- COMMENTED: THIS IS UNCHECKED CHARGES VERSION, user must check himself later!
            //if( v->GetParamN()->Charge() > 0 && v->GetParamP()->Charge() > 0 ) continue;
            //if( v->GetParamN()->Charge() < 0 && v->GetParamP()->Charge() < 0 ) continue;
        }

        if (v->GetD(xPrimaryVertex,yPrimaryVertex,zPrimaryVertex)<fDV0min) continue;
        vtcs.AddLast(v);
    }
    nV0=vtcs.GetEntriesFast();

    // stores relevant tracks in another array
    Int_t nentr=(Int_t)event->GetNumberOfTracks();
    TArrayI trk(nentr); Int_t ntr=0;
    for (i=0; i<nentr; i++) {
        AliESDtrack *esdtr=event->GetTrack(i);

        ULong_t status=esdtr->GetStatus();

        if ((status&AliESDtrack::kITSrefit)==0)
            if ((status&AliESDtrack::kTPCrefit)==0) continue;

        //Track pre-selection: clusters
        if (esdtr->GetTPCNcls() < fMinClusters ) continue;

        if (TMath::Abs(esdtr->GetD(xPrimaryVertex,yPrimaryVertex,b))<fDBachMin) continue;

        trk[ntr++]=i;
    }

    Double_t massLambda=1.11568;
    Int_t ncasc=0;

    // Looking for both cascades and anti-cascades simultaneously

    for (i=0; i<nV0; i++) { //loop on V0s

        AliESDv0 *v=(AliESDv0*)vtcs.UncheckedAt(i);
        AliESDv0 v0(*v);

        Float_t lMassAsLambda     = 0;
        Float_t lMassAsAntiLambda = 0;

        v0.ChangeMassHypothesis(kLambda0); // the v0 must be Lambda
        lMassAsLambda = v0.GetEffMass();

        v0.ChangeMassHypothesis(kLambda0Bar); // the v0 must be Lambda
        lMassAsAntiLambda = v0.GetEffMass();

        //Only disregard if it does not pass any of the desired hypotheses
        if (TMath::Abs(lMassAsLambda-massLambda)>fMassWin &&
            TMath::Abs(lMassAsAntiLambda-massLambda)>fMassWin) continue;

        for (Int_t j=0; j<ntr; j++) {//loop on tracks
            Int_t bidx=trk[j];
            //Check if different tracks are used all times
            if (bidx==v0.GetIndex(0)) continue; //Bo:  consistency 0 for neg
            if (bidx==v0.GetIndex(1)) continue; //Bo:  consistency 0 for neg
            if (v0.GetIndex(0)==v0.GetIndex(1)) continue; //Bo:  consistency 0 for neg

            AliESDtrack *btrk=event->GetTrack(bidx);

            //Do not check charges!
            AliESDv0 *pv0=&v0;
            AliExternalTrackParam bt(*btrk), *pbt=&bt;

            Double_t dca=PropagateToDCA(pv0,pbt,b);
            if (dca > fDCAmax) continue;

            //eta cut - test
            if (TMath::Abs(pbt->Eta())>fMaxEta) continue;

            AliESDcascade cascade(*pv0,*pbt,bidx);//constucts a cascade candidate

            Double_t x,y,z; cascade.GetXYZcascade(x,y,z); // Bo: bug correction
            Double_t r2=x*x + y*y;
            if (r2 > fRmax*fRmax) continue;   // condition on fiducial zone
            if (r2 < fRmin*fRmin) continue;

            Double_t pxV0,pyV0,pzV0;
            pv0->GetPxPyPz(pxV0,pyV0,pzV0);
            if (x*pxV0+y*pyV0+z*pzV0 < 0) continue; //causality

            Double_t x1,y1,z1; pv0->GetXYZ(x1,y1,z1);
            if (r2 > (x1*x1+y1*y1)) continue;

            if (cascade.GetCascadeCosineOfPointingAngle(xPrimaryVertex,yPrimaryVertex,zPrimaryVertex) <fCPAmin) continue; //condition on the cascade pointing angle

            cascade.SetDcaXiDaughters(dca);
            event->AddCascade(&cascade);
            ncasc++;
        } // end loop tracks
    } // end loop V0s

    Info("V0sTracks2CascadeVertices","Number of reconstructed cascades: %d",ncasc);

    return 0;
}

Double_t AliCascadeVertexerUncheckedCharges::Det(Double_t a00, Double_t a01, Double_t a10, Double_t a11) const {
    //--------------------------------------------------------------------
    // This function calculates locally a 2x2 determinant
    //--------------------------------------------------------------------
    return a00*a11 - a01*a10;
}

Double_t AliCascadeVertexerUncheckedCharges::Det(Double_t a00,Double_t a01,Double_t a02,
                                      Double_t a10,Double_t a11,Double_t a12,
                                      Double_t a20,Double_t a21,Double_t a22) const {
    //--------------------------------------------------------------------
    // This function calculates locally a 3x3 determinant
    //--------------------------------------------------------------------
    return  a00*Det(a11,a12,a21,a22)-a01*Det(a10,a12,a20,a22)+a02*Det(a10,a11,a20,a21);
}

Double_t AliCascadeVertexerUncheckedCharges::PropagateToDCA(AliESDv0 *v, AliExternalTrackParam *t, Double_t b) {
    //--------------------------------------------------------------------
    // This function returns the DCA between the V0 and the track
    //--------------------------------------------------------------------
    Double_t alpha=t->GetAlpha(), cs1=TMath::Cos(alpha), sn1=TMath::Sin(alpha);
    Double_t r[3]; t->GetXYZ(r);
    Double_t x1=r[0], y1=r[1], z1=r[2];
    Double_t p[3]; t->GetPxPyPz(p);
    Double_t px1=p[0], py1=p[1], pz1=p[2];

    Double_t x2,y2,z2;     // position and momentum of V0
    Double_t px2,py2,pz2;

    v->GetXYZ(x2,y2,z2);
    v->GetPxPyPz(px2,py2,pz2);

    // calculation dca

    Double_t dd= Det(x2-x1,y2-y1,z2-z1,px1,py1,pz1,px2,py2,pz2);
    Double_t ax= Det(py1,pz1,py2,pz2);
    Double_t ay=-Det(px1,pz1,px2,pz2);
    Double_t az= Det(px1,py1,px2,py2);

    Double_t dca=TMath::Abs(dd)/TMath::Sqrt(ax*ax + ay*ay + az*az);

    //points of the DCA
    Double_t t1 = Det(x2-x1,y2-y1,z2-z1,px2,py2,pz2,ax,ay,az)/
    Det(px1,py1,pz1,px2,py2,pz2,ax,ay,az);

    x1 += px1*t1; y1 += py1*t1; //z1 += pz1*t1;

    //propagate track to the points of DCA

    x1=x1*cs1 + y1*sn1;
    if (!t->PropagateTo(x1,b)) {
        Error("PropagateToDCA","Propagation failed !");
        return 1.e+33;
    }

    return dca;
}

//________________________________________________________________________
void AliCascadeVertexerUncheckedCharges::CheckChargeV0(AliESDv0 *v0)
{
    // This function checks charge of negative and positive daughter tracks.
    // If incorrectly defined (onfly vertexer), swaps out.
    if( v0->GetParamN()->Charge() > 0 && v0->GetParamP()->Charge() < 0 ) {
        //V0 daughter track swapping is required! Note: everything is swapped here... P->N, N->P
        Long_t lCorrectNidx = v0->GetPindex();
        Long_t lCorrectPidx = v0->GetNindex();
        Double32_t	lCorrectNmom[3];
        Double32_t	lCorrectPmom[3];
        v0->GetPPxPyPz( lCorrectNmom[0], lCorrectNmom[1], lCorrectNmom[2] );
        v0->GetNPxPyPz( lCorrectPmom[0], lCorrectPmom[1], lCorrectPmom[2] );

        AliExternalTrackParam	lCorrectParamN(
                                               v0->GetParamP()->GetX() ,
                                               v0->GetParamP()->GetAlpha() ,
                                               v0->GetParamP()->GetParameter() ,
                                               v0->GetParamP()->GetCovariance()
                                               );
        AliExternalTrackParam	lCorrectParamP(
                                               v0->GetParamN()->GetX() ,
                                               v0->GetParamN()->GetAlpha() ,
                                               v0->GetParamN()->GetParameter() ,
                                               v0->GetParamN()->GetCovariance()
                                               );
        lCorrectParamN.SetMostProbablePt( v0->GetParamP()->GetMostProbablePt() );
        lCorrectParamP.SetMostProbablePt( v0->GetParamN()->GetMostProbablePt() );

        //Get Variables___________________________________________________
        Double_t lDcaV0Daughters = v0 -> GetDcaV0Daughters();
        Double_t lCosPALocal     = v0 -> GetV0CosineOfPointingAngle();
        Bool_t lOnFlyStatusLocal = v0 -> GetOnFlyStatus();

        //Create Replacement Object_______________________________________
        AliESDv0 *v0correct = new AliESDv0(lCorrectParamN,lCorrectNidx,lCorrectParamP,lCorrectPidx);
        v0correct->SetDcaV0Daughters          ( lDcaV0Daughters   );
        v0correct->SetV0CosineOfPointingAngle ( lCosPALocal       );
        v0correct->ChangeMassHypothesis       ( kK0Short          );
        v0correct->SetOnFlyStatus             ( lOnFlyStatusLocal );

        //Reverse Cluster info..._________________________________________
        v0correct->SetClusters( v0->GetClusters( 1 ), v0->GetClusters ( 0 ) );

        *v0 = *v0correct;
        //Proper cleanup..._______________________________________________
        v0correct->Delete();
        v0correct = 0x0;

        //Just another cross-check and output_____________________________
        if( v0->GetParamN()->Charge() > 0 && v0->GetParamP()->Charge() < 0 ) {
            AliWarning("Found Swapped Charges, tried to correct but something FAILED!");
        } else {
            //AliWarning("Found Swapped Charges and fixed.");
        }
        //________________________________________________________________
    } else {
        //Don't touch it! ---
        //Printf("Ah, nice. Charges are already ordered...");
    }
    return;
}

<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# include <GL/glew.h>
# include <GLFW/glfw3.h>
# include "GLRasterizerState.hpp"

namespace s3d
{
	//namespace detail
	//{
	//	static constexpr uint32 blendOpTable[6] =
	//	{
	//		0,
	//		GL_FUNC_ADD,
	//		GL_FUNC_SUBTRACT,
	//		GL_FUNC_REVERSE_SUBTRACT,
	//		GL_MIN,
	//		GL_MAX
	//	};

	//	static constexpr uint32 blendTable[20] =
	//	{
	//		0,
	//		GL_ZERO,
	//		GL_ONE,
	//		GL_SRC_COLOR,
	//		GL_ONE_MINUS_SRC_COLOR,
	//		GL_SRC_ALPHA,
	//		GL_ONE_MINUS_SRC_ALPHA,
	//		GL_DST_ALPHA,
	//		GL_ONE_MINUS_DST_ALPHA,
	//		GL_DST_COLOR,
	//		GL_ONE_MINUS_DST_COLOR,
	//		GL_SRC_ALPHA_SATURATE,
	//		0,
	//		0,
	//		GL_CONSTANT_COLOR,
	//		GL_ONE_MINUS_CONSTANT_COLOR,
	//		GL_SRC1_COLOR,
	//		GL_ONE_MINUS_SRC1_COLOR,
	//		GL_SRC1_ALPHA,
	//		GL_ONE_MINUS_SRC1_ALPHA,
	//	};
	//}

	GLRasterizerState::GLRasterizerState()
	{
		::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

		::glDisable(GL_CULL_FACE);

		::glDisable(GL_SCISSOR_TEST);

		::glDisable(GL_POLYGON_OFFSET_LINE);
		::glDisable(GL_POLYGON_OFFSET_FILL);
	}

	void GLRasterizerState::set(const RasterizerState& state)
	{
		if (state == m_currentState)
		{
			return;
		}

		if (state.fillMode != m_currentState.fillMode)
		{
			::glPolygonMode(GL_FRONT_AND_BACK, state.fillMode == FillMode::Solid ? GL_FILL : GL_LINE);
		}

		if (state.cullMode != m_currentState.cullMode)
		{
			if (state.cullMode == CullMode::None)
			{
				::glDisable(GL_CULL_FACE);
			}
			else
			{
				::glEnable(GL_CULL_FACE);

				::glFrontFace(GL_CW);

				::glCullFace(state.cullMode == CullMode::Front ? GL_FRONT : GL_BACK);
			}
		}

		if (state.scissorEnable != m_currentState.scissorEnable)
		{
			if (state.scissorEnable)
			{
				::glEnable(GL_SCISSOR_TEST);
			}
			else
			{
				::glDisable(GL_SCISSOR_TEST);
			}
		}

		if (state.depthBias != m_currentState.depthBias)
		{
			if (state.depthBias)
			{
				::glEnable(GL_POLYGON_OFFSET_LINE);
				::glEnable(GL_POLYGON_OFFSET_FILL);
				::glPolygonOffset(0, state.depthBias);
			}
			else
			{
				::glDisable(GL_POLYGON_OFFSET_LINE);
				::glDisable(GL_POLYGON_OFFSET_FILL);
			}
		}

		m_currentState = state;
	}
}
<commit_msg>OpenGL Cull 修正<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# include <GL/glew.h>
# include <GLFW/glfw3.h>
# include "GLRasterizerState.hpp"

namespace s3d
{
	GLRasterizerState::GLRasterizerState()
	{
		::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

		::glDisable(GL_CULL_FACE);

		::glDisable(GL_SCISSOR_TEST);

		::glDisable(GL_POLYGON_OFFSET_LINE);
		::glDisable(GL_POLYGON_OFFSET_FILL);
	}

	void GLRasterizerState::set(const RasterizerState& state)
	{
		if (state == m_currentState)
		{
			return;
		}

		if (state.fillMode != m_currentState.fillMode)
		{
			::glPolygonMode(GL_FRONT_AND_BACK, state.fillMode == FillMode::Solid ? GL_FILL : GL_LINE);
		}

		if (state.cullMode != m_currentState.cullMode)
		{
			if (state.cullMode == CullMode::None)
			{
				::glDisable(GL_CULL_FACE);
			}
			else
			{
				::glEnable(GL_CULL_FACE);

				::glFrontFace(GL_CW);

				// CullMode::Front = GL_BACK, CullMode::Back = GL_FRONT
				::glCullFace(state.cullMode == CullMode::Front ? GL_BACK : GL_FRONT);
			}
		}

		if (state.scissorEnable != m_currentState.scissorEnable)
		{
			if (state.scissorEnable)
			{
				::glEnable(GL_SCISSOR_TEST);
			}
			else
			{
				::glDisable(GL_SCISSOR_TEST);
			}
		}

		if (state.depthBias != m_currentState.depthBias)
		{
			if (state.depthBias)
			{
				::glEnable(GL_POLYGON_OFFSET_LINE);
				::glEnable(GL_POLYGON_OFFSET_FILL);
				::glPolygonOffset(0, state.depthBias);
			}
			else
			{
				::glDisable(GL_POLYGON_OFFSET_LINE);
				::glDisable(GL_POLYGON_OFFSET_FILL);
			}
		}

		m_currentState = state;
	}
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <cassert>
#include "system.h"
#include "errors.h"
#include "utils.h"

int System::installMemory(MemoryModule &mod, SizeType offset, SizeType size) {
    int status = ERR_SUCCESS;

    // NB: if(size <= 0 || /* overflow */offset + size < offset) {
    if(offset + size <= offset) {
        status = ERR_BADRANGE;
    } else {
        MemoryInstance overlap = resolveAtMost(offset + size - 1);
        if(overlap) {
            SizeType overlapEnd = overlap.offset + overlap.length - 1;
            if(overlapEnd >= offset) {
                status = ERR_CONFLICT;
            }
        }
    }

    if(status == ERR_SUCCESS) {
        mem.emplace(offset,  MemoryInstance(&mod, offset, size));
    }
    return status;
}

int System::removeMemory(SizeType offset) {
    MemMap::size_type erased = mem.erase(offset);
    assert(erased <= 1);
    int status = erased ? ERR_SUCCESS : ERR_BADRANGE;
    return status;
}

int System::bindPort(PortSocket &sock, PortType port) {
    throw "Not Implemented";
}

int System::releasePort(PortType port) {
    throw "Not Implemented";
}

int System::readMemory(SizeType offset, SizeType len, void *data) const {
    return memoryLoop(offset, len, data, false);
}

int System::writeMemory(SizeType offset, SizeType len, const void *data) const {
    return memoryLoop(offset, len, data, true);
}

int System::readPort(PortType port, SizeType len, void *data) const {
    throw "Not Implemented";
}

int System::writePort(PortType port, SizeType len, const void *data) const {
    throw "Not Implemented";
}

// Find installed module with base address <= address
System::MemoryInstance System::resolveAtMost(SizeType address) const {
    auto iterator = mem.lower_bound(address);
    if(iterator->second.offset != address) {
        if (iterator == mem.cbegin()) {
            iterator = mem.cend();
        } else if(iterator != mem.cend()) {
            iterator--;
        }
    }
    return iterator->second;
}

int System::memoryLoop(SizeType offset, SizeType len, const void *data, bool write) const {
    int status = ERR_SUCCESS;
    while(len > 0) {
        MemoryInstance src = resolveAtMost(offset);
        if(!src) {
            status = ERR_BADRANGE;
        } else {
            SizeType srcOff = offset - src.offset;
            SizeType srcLen = std::min(src.length - srcOff, len);
            if(write) {
                status = src.mod->writeMemory(srcOff, srcLen, data);
            } else {
                status = src.mod->readMemory(srcOff, srcLen, /* HACK */(void*)(data));
            }
            if(status == ERR_SUCCESS)
            {
                len -= srcLen;
                offset += srcLen;
                data = advancePtr(data, srcLen);
            } else {
                break;
            }
        }
    }
    return status;
}<commit_msg>Remove duplicate comment<commit_after>#include <algorithm>
#include <cassert>
#include "system.h"
#include "errors.h"
#include "utils.h"

int System::installMemory(MemoryModule &mod, SizeType offset, SizeType size) {
    int status = ERR_SUCCESS;

    // NB: if(size <= 0 || /* overflow */offset + size < offset) {
    if(offset + size <= offset) {
        status = ERR_BADRANGE;
    } else {
        MemoryInstance overlap = resolveAtMost(offset + size - 1);
        if(overlap) {
            SizeType overlapEnd = overlap.offset + overlap.length - 1;
            if(overlapEnd >= offset) {
                status = ERR_CONFLICT;
            }
        }
    }

    if(status == ERR_SUCCESS) {
        mem.emplace(offset,  MemoryInstance(&mod, offset, size));
    }
    return status;
}

int System::removeMemory(SizeType offset) {
    MemMap::size_type erased = mem.erase(offset);
    assert(erased <= 1);
    int status = erased ? ERR_SUCCESS : ERR_BADRANGE;
    return status;
}

int System::bindPort(PortSocket &sock, PortType port) {
    throw "Not Implemented";
}

int System::releasePort(PortType port) {
    throw "Not Implemented";
}

int System::readMemory(SizeType offset, SizeType len, void *data) const {
    return memoryLoop(offset, len, data, false);
}

int System::writeMemory(SizeType offset, SizeType len, const void *data) const {
    return memoryLoop(offset, len, data, true);
}

int System::readPort(PortType port, SizeType len, void *data) const {
    throw "Not Implemented";
}

int System::writePort(PortType port, SizeType len, const void *data) const {
    throw "Not Implemented";
}

System::MemoryInstance System::resolveAtMost(SizeType address) const {
    auto iterator = mem.lower_bound(address);
    if(iterator->second.offset != address) {
        if (iterator == mem.cbegin()) {
            iterator = mem.cend();
        } else if(iterator != mem.cend()) {
            iterator--;
        }
    }
    return iterator->second;
}

int System::memoryLoop(SizeType offset, SizeType len, const void *data, bool write) const {
    int status = ERR_SUCCESS;
    while(len > 0) {
        MemoryInstance src = resolveAtMost(offset);
        if(!src) {
            status = ERR_BADRANGE;
        } else {
            SizeType srcOff = offset - src.offset;
            SizeType srcLen = std::min(src.length - srcOff, len);
            if(write) {
                status = src.mod->writeMemory(srcOff, srcLen, data);
            } else {
                status = src.mod->readMemory(srcOff, srcLen, /* HACK */(void*)(data));
            }
            if(status == ERR_SUCCESS)
            {
                len -= srcLen;
                offset += srcLen;
                data = advancePtr(data, srcLen);
            } else {
                break;
            }
        }
    }
    return status;
}<|endoftext|>


<commit_before>/*
 * Copyright 2010-2020 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include "bx_p.h"
#include <bx/os.h>
#include <bx/thread.h>

#if BX_CONFIG_SUPPORTS_THREADING

#if BX_PLATFORM_WINDOWS && !BX_CRT_NONE
#	include <bx/string.h>
#endif

#if BX_CRT_NONE
#	include "crt0.h"
#elif  BX_PLATFORM_ANDROID \
	|| BX_PLATFORM_BSD     \
	|| BX_PLATFORM_HAIKU   \
	|| BX_PLATFORM_LINUX   \
	|| BX_PLATFORM_IOS     \
	|| BX_PLATFORM_OSX     \
	|| BX_PLATFORM_PS4     \
	|| BX_PLATFORM_RPI
#	include <pthread.h>
#	if defined(__FreeBSD__)
#		include <pthread_np.h>
#	endif
#	if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
#		include <sys/prctl.h>
#	endif // BX_PLATFORM_
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
#	include <windows.h>
#	include <limits.h>
#	include <errno.h>
#	if BX_PLATFORM_WINRT
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::System::Threading;
#	endif // BX_PLATFORM_WINRT
#endif // BX_PLATFORM_

namespace bx
{
	static AllocatorI* getAllocator()
	{
		static DefaultAllocator s_allocator;
		return &s_allocator;
	}

	struct ThreadInternal
	{
#if BX_CRT_NONE
		static int32_t threadFunc(void* _arg);
		int32_t m_handle;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		static DWORD WINAPI threadFunc(LPVOID _arg);
		HANDLE m_handle;
		DWORD  m_threadId;
#elif BX_PLATFORM_POSIX
		static void* threadFunc(void* _arg);
		pthread_t m_handle;
#endif // BX_PLATFORM_
	};

#if BX_CRT_NONE
	int32_t ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE \
	|| BX_PLATFORM_WINRT
	DWORD WINAPI ThreadInternal::threadFunc(LPVOID _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#else
	void* ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		cast.i = thread->entry();
		return cast.ptr;
	}
#endif // BX_PLATFORM_

	Thread::Thread()
		: m_fn(NULL)
		, m_userData(NULL)
		, m_queue(getAllocator() )
		, m_stackSize(0)
		, m_exitCode(kExitSuccess)
		, m_running(false)
	{
		BX_STATIC_ASSERT(sizeof(ThreadInternal) <= sizeof(m_internal) );

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = INT32_MIN;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle   = INVALID_HANDLE_VALUE;
		ti->m_threadId = UINT32_MAX;
#elif BX_PLATFORM_POSIX
		ti->m_handle = 0;
#endif // BX_PLATFORM_
	}

	Thread::~Thread()
	{
		if (m_running)
		{
			shutdown();
		}
	}

	bool Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
	{
		BX_ASSERT(!m_running, "Already running!");

		m_fn = _fn;
		m_userData = _userData;
		m_stackSize = _stackSize;

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = crt0::threadCreate(&ti->threadFunc, _userData, m_stackSize, _name);

		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle = ::CreateThread(NULL
				, m_stackSize
				, (LPTHREAD_START_ROUTINE)ti->threadFunc
				, this
				, 0
				, NULL
				);
		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif BX_PLATFORM_WINRT
		ti->m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);

		if (NULL == ti->m_handle)
		{
			return false;
		}

		auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
			{
				m_exitCode = ti->threadFunc(this);
				SetEvent(ti->m_handle);
			}
			, CallbackContext::Any
			);

		ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
#elif BX_PLATFORM_POSIX
		int result;
		BX_UNUSED(result);

		pthread_attr_t attr;
		result = pthread_attr_init(&attr);
		BX_WARN(0 == result, "pthread_attr_init failed! %d", result);
		if (0 != result)
		{
			return false;
		}

		if (0 != m_stackSize)
		{
			result = pthread_attr_setstacksize(&attr, m_stackSize);
			BX_WARN(0 == result, "pthread_attr_setstacksize failed! %d", result);

			if (0 != result)
			{
				return false;
			}
		}

		result = pthread_create(&ti->m_handle, &attr, &ti->threadFunc, this);
		BX_WARN(0 == result, "pthread_attr_setschedparam failed! %d", result);
		if (0 != result)
		{
			return false;
		}
#else
#	error "Not implemented!"
#endif // BX_PLATFORM_

		m_running = true;
		m_sem.wait();

		if (NULL != _name)
		{
			setThreadName(_name);
		}

		return true;
	}

	void Thread::shutdown()
	{
		BX_ASSERT(m_running, "Not running!");
		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		crt0::threadJoin(ti->m_handle, NULL);
#elif BX_PLATFORM_WINDOWS
		WaitForSingleObject(ti->m_handle, INFINITE);
		GetExitCodeThread(ti->m_handle, (DWORD*)&m_exitCode);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_WINRT || BX_PLATFORM_XBOXONE
		WaitForSingleObjectEx(ti->m_handle, INFINITE, FALSE);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_POSIX
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		pthread_join(ti->m_handle, &cast.ptr);
		m_exitCode = cast.i;
		ti->m_handle = 0;
#endif // BX_PLATFORM_

		m_running = false;
	}

	bool Thread::isRunning() const
	{
		return m_running;
	}

	int32_t Thread::getExitCode() const
	{
		return m_exitCode;
	}

	void Thread::setThreadName(const char* _name)
	{
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		BX_UNUSED(ti);
#if BX_CRT_NONE
		BX_UNUSED(_name);
#elif  BX_PLATFORM_OSX \
	|| BX_PLATFORM_IOS
		pthread_setname_np(_name);
#elif (BX_CRT_GLIBC >= 21200) && ! BX_PLATFORM_HURD
		pthread_setname_np(ti->m_handle, _name);
#elif BX_PLATFORM_LINUX
		prctl(PR_SET_NAME,_name, 0, 0, 0);
#elif BX_PLATFORM_BSD
#	if defined(__NetBSD__)
		pthread_setname_np(ti->m_handle, "%s", (void*)_name);
#	else
		pthread_set_name_np(ti->m_handle, _name);
#	endif // defined(__NetBSD__)
#elif BX_PLATFORM_WINDOWS
		// Try to use the new thread naming API from Win10 Creators update onwards if we have it
		typedef HRESULT (WINAPI *SetThreadDescriptionProc)(HANDLE, PCWSTR);
		SetThreadDescriptionProc SetThreadDescription = dlsym<SetThreadDescriptionProc>((void*)GetModuleHandleA("Kernel32.dll"), "SetThreadDescription");

		if (NULL != SetThreadDescription)
		{
			uint32_t length = (uint32_t)bx::strLen(_name)+1;
			uint32_t size = length*sizeof(wchar_t);
			wchar_t* name = (wchar_t*)alloca(size);
			mbstowcs(name, _name, size-2);
			SetThreadDescription(ti->m_handle, name);
		}
#	if BX_COMPILER_MSVC
#		pragma pack(push, 8)
			struct ThreadName
			{
				DWORD  type;
				LPCSTR name;
				DWORD  id;
				DWORD  flags;
			};
#		pragma pack(pop)
			ThreadName tn;
			tn.type  = 0x1000;
			tn.name  = _name;
			tn.id    = ti->m_threadId;
			tn.flags = 0;

			__try
			{
				RaiseException(0x406d1388
						, 0
						, sizeof(tn)/4
						, reinterpret_cast<ULONG_PTR*>(&tn)
						);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
			}
#	endif // BX_COMPILER_MSVC
#else
		BX_UNUSED(_name);
#endif // BX_PLATFORM_
	}

	void Thread::push(void* _ptr)
	{
		m_queue.push(_ptr);
	}

	void* Thread::pop()
	{
		void* ptr = m_queue.pop();
		return ptr;
	}

	int32_t Thread::entry()
	{
#if BX_PLATFORM_WINDOWS
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		ti->m_threadId = ::GetCurrentThreadId();
#endif // BX_PLATFORM_WINDOWS

		m_sem.post();
		int32_t result = m_fn(this, m_userData);
		return result;
	}

	struct TlsDataInternal
	{
#if BX_CRT_NONE
#elif BX_PLATFORM_WINDOWS
		uint32_t m_id;
#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)
		pthread_key_t m_id;
#endif // BX_PLATFORM_*
	};

#if BX_CRT_NONE
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	void* TlsData::get() const
	{
		return NULL;
	}

	void TlsData::set(void* _ptr)
	{
		BX_UNUSED(_ptr);

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}
#elif BX_PLATFORM_WINDOWS
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		ti->m_id = TlsAlloc();
		BX_ASSERT(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BOOL result = TlsFree(ti->m_id);
		BX_ASSERT(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return TlsGetValue(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		TlsSetValue(ti->m_id, _ptr);
	}

#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)

	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_create(&ti->m_id, NULL);
		BX_ASSERT(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_delete(ti->m_id);
		BX_ASSERT(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return pthread_getspecific(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_setspecific(ti->m_id, _ptr);
		BX_ASSERT(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
	}
#endif // BX_PLATFORM_*

} // namespace bx

#endif // BX_CONFIG_SUPPORTS_THREADING
<commit_msg>Add flag to avoid consuming windows runtime in winrt c++ applications (#259)<commit_after>/*
 * Copyright 2010-2020 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include "bx_p.h"
#include <bx/os.h>
#include <bx/thread.h>

#if BX_CONFIG_SUPPORTS_THREADING

#if BX_PLATFORM_WINDOWS && !BX_CRT_NONE
#	include <bx/string.h>
#endif

#if BX_CRT_NONE
#	include "crt0.h"
#elif  BX_PLATFORM_ANDROID \
	|| BX_PLATFORM_BSD     \
	|| BX_PLATFORM_HAIKU   \
	|| BX_PLATFORM_LINUX   \
	|| BX_PLATFORM_IOS     \
	|| BX_PLATFORM_OSX     \
	|| BX_PLATFORM_PS4     \
	|| BX_PLATFORM_RPI
#	include <pthread.h>
#	if defined(__FreeBSD__)
#		include <pthread_np.h>
#	endif
#	if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
#		include <sys/prctl.h>
#	endif // BX_PLATFORM_
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE \
	|| BX_PLATFORM_WINRT
#	include <windows.h>
#	include <limits.h>
#	include <errno.h>
#endif // BX_PLATFORM_

namespace bx
{
	static AllocatorI* getAllocator()
	{
		static DefaultAllocator s_allocator;
		return &s_allocator;
	}

	struct ThreadInternal
	{
#if BX_CRT_NONE
		static int32_t threadFunc(void* _arg);
		int32_t m_handle;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		static DWORD WINAPI threadFunc(LPVOID _arg);
		HANDLE m_handle;
		DWORD  m_threadId;
#elif BX_PLATFORM_POSIX
		static void* threadFunc(void* _arg);
		pthread_t m_handle;
#endif // BX_PLATFORM_
	};

#if BX_CRT_NONE
	int32_t ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE \
	|| BX_PLATFORM_WINRT
	DWORD WINAPI ThreadInternal::threadFunc(LPVOID _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#else
	void* ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		cast.i = thread->entry();
		return cast.ptr;
	}
#endif // BX_PLATFORM_

	Thread::Thread()
		: m_fn(NULL)
		, m_userData(NULL)
		, m_queue(getAllocator() )
		, m_stackSize(0)
		, m_exitCode(kExitSuccess)
		, m_running(false)
	{
		BX_STATIC_ASSERT(sizeof(ThreadInternal) <= sizeof(m_internal) );

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = INT32_MIN;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle   = INVALID_HANDLE_VALUE;
		ti->m_threadId = UINT32_MAX;
#elif BX_PLATFORM_POSIX
		ti->m_handle = 0;
#endif // BX_PLATFORM_
	}

	Thread::~Thread()
	{
		if (m_running)
		{
			shutdown();
		}
	}

	bool Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
	{
		BX_ASSERT(!m_running, "Already running!");

		m_fn = _fn;
		m_userData = _userData;
		m_stackSize = _stackSize;

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = crt0::threadCreate(&ti->threadFunc, _userData, m_stackSize, _name);

		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE \
	|| BX_PLATFORM_WINRT
		ti->m_handle = ::CreateThread(NULL
				, m_stackSize
				, (LPTHREAD_START_ROUTINE)ti->threadFunc
				, this
				, 0
				, NULL
				);
		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif BX_PLATFORM_POSIX
		int result;
		BX_UNUSED(result);

		pthread_attr_t attr;
		result = pthread_attr_init(&attr);
		BX_WARN(0 == result, "pthread_attr_init failed! %d", result);
		if (0 != result)
		{
			return false;
		}

		if (0 != m_stackSize)
		{
			result = pthread_attr_setstacksize(&attr, m_stackSize);
			BX_WARN(0 == result, "pthread_attr_setstacksize failed! %d", result);

			if (0 != result)
			{
				return false;
			}
		}

		result = pthread_create(&ti->m_handle, &attr, &ti->threadFunc, this);
		BX_WARN(0 == result, "pthread_attr_setschedparam failed! %d", result);
		if (0 != result)
		{
			return false;
		}
#else
#	error "Not implemented!"
#endif // BX_PLATFORM_

		m_running = true;
		m_sem.wait();

		if (NULL != _name)
		{
			setThreadName(_name);
		}

		return true;
	}

	void Thread::shutdown()
	{
		BX_ASSERT(m_running, "Not running!");
		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		crt0::threadJoin(ti->m_handle, NULL);
#elif BX_PLATFORM_WINDOWS
		WaitForSingleObject(ti->m_handle, INFINITE);
		GetExitCodeThread(ti->m_handle, (DWORD*)&m_exitCode);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_WINRT || BX_PLATFORM_XBOXONE
		WaitForSingleObjectEx(ti->m_handle, INFINITE, FALSE);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_POSIX
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		pthread_join(ti->m_handle, &cast.ptr);
		m_exitCode = cast.i;
		ti->m_handle = 0;
#endif // BX_PLATFORM_

		m_running = false;
	}

	bool Thread::isRunning() const
	{
		return m_running;
	}

	int32_t Thread::getExitCode() const
	{
		return m_exitCode;
	}

	void Thread::setThreadName(const char* _name)
	{
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		BX_UNUSED(ti);
#if BX_CRT_NONE
		BX_UNUSED(_name);
#elif  BX_PLATFORM_OSX \
	|| BX_PLATFORM_IOS
		pthread_setname_np(_name);
#elif (BX_CRT_GLIBC >= 21200) && ! BX_PLATFORM_HURD
		pthread_setname_np(ti->m_handle, _name);
#elif BX_PLATFORM_LINUX
		prctl(PR_SET_NAME,_name, 0, 0, 0);
#elif BX_PLATFORM_BSD
#	if defined(__NetBSD__)
		pthread_setname_np(ti->m_handle, "%s", (void*)_name);
#	else
		pthread_set_name_np(ti->m_handle, _name);
#	endif // defined(__NetBSD__)
#elif BX_PLATFORM_WINDOWS
		// Try to use the new thread naming API from Win10 Creators update onwards if we have it
		typedef HRESULT (WINAPI *SetThreadDescriptionProc)(HANDLE, PCWSTR);
		SetThreadDescriptionProc SetThreadDescription = dlsym<SetThreadDescriptionProc>((void*)GetModuleHandleA("Kernel32.dll"), "SetThreadDescription");

		if (NULL != SetThreadDescription)
		{
			uint32_t length = (uint32_t)bx::strLen(_name)+1;
			uint32_t size = length*sizeof(wchar_t);
			wchar_t* name = (wchar_t*)alloca(size);
			mbstowcs(name, _name, size-2);
			SetThreadDescription(ti->m_handle, name);
		}
#	if BX_COMPILER_MSVC
#		pragma pack(push, 8)
			struct ThreadName
			{
				DWORD  type;
				LPCSTR name;
				DWORD  id;
				DWORD  flags;
			};
#		pragma pack(pop)
			ThreadName tn;
			tn.type  = 0x1000;
			tn.name  = _name;
			tn.id    = ti->m_threadId;
			tn.flags = 0;

			__try
			{
				RaiseException(0x406d1388
						, 0
						, sizeof(tn)/4
						, reinterpret_cast<ULONG_PTR*>(&tn)
						);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
			}
#	endif // BX_COMPILER_MSVC
#else
		BX_UNUSED(_name);
#endif // BX_PLATFORM_
	}

	void Thread::push(void* _ptr)
	{
		m_queue.push(_ptr);
	}

	void* Thread::pop()
	{
		void* ptr = m_queue.pop();
		return ptr;
	}

	int32_t Thread::entry()
	{
#if BX_PLATFORM_WINDOWS
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		ti->m_threadId = ::GetCurrentThreadId();
#endif // BX_PLATFORM_WINDOWS

		m_sem.post();
		int32_t result = m_fn(this, m_userData);
		return result;
	}

	struct TlsDataInternal
	{
#if BX_CRT_NONE
#elif BX_PLATFORM_WINDOWS
		uint32_t m_id;
#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)
		pthread_key_t m_id;
#endif // BX_PLATFORM_*
	};

#if BX_CRT_NONE
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	void* TlsData::get() const
	{
		return NULL;
	}

	void TlsData::set(void* _ptr)
	{
		BX_UNUSED(_ptr);

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}
#elif BX_PLATFORM_WINDOWS
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		ti->m_id = TlsAlloc();
		BX_ASSERT(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BOOL result = TlsFree(ti->m_id);
		BX_ASSERT(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return TlsGetValue(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		TlsSetValue(ti->m_id, _ptr);
	}

#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)

	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_create(&ti->m_id, NULL);
		BX_ASSERT(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_delete(ti->m_id);
		BX_ASSERT(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return pthread_getspecific(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_setspecific(ti->m_id, _ptr);
		BX_ASSERT(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
	}
#endif // BX_PLATFORM_*

} // namespace bx

#endif // BX_CONFIG_SUPPORTS_THREADING
<|endoftext|>


<commit_before>// Copyright 2016 Chris Drake
//
// 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 <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <boost/optional.hpp>
#include <cryptominisat4/cryptominisat.h>

#include "boolexpr/boolexpr.h"

using namespace boolexpr;

var_t
Operator::to_con1(Context& ctx, string const & auxvarname,
                  uint32_t& index, var2op_t& constraints) const
{
    auto key = ctx.get_var(auxvarname + "_" + std::to_string(index++));
    auto val = to_con2(ctx, auxvarname, index, constraints);

    constraints.insert({key, val});

    return key;
}

op_t
Operator::to_con2(Context& ctx, string const & auxvarname,
                  uint32_t& index, var2op_t& constraints) const
{
    bool found_subop = false;
    vector<bx_t> _args;

    // NOTE: do not use transform, b/c there's mutable state
    for (bx_t const & arg : args) {
        if (IS_OP(arg)) {
            found_subop = true;
            auto subop = std::static_pointer_cast<Operator const>(arg);
            auto x = subop->to_con1(ctx, auxvarname, index, constraints);
            _args.push_back(x);
        }
        else {
            _args.push_back(arg);
        }
    }

    if (found_subop)
        return from_args(std::move(_args));

    return std::static_pointer_cast<Operator const>(shared_from_this());
}

bx_t
Atom::tseytin(Context&, string const &) const
{
    return shared_from_this();
}

bx_t
Operator::tseytin(Context& ctx, string const & auxvarname) const
{
    uint32_t index {0};
    var2op_t constraints;

    auto top = to_con1(ctx, auxvarname, index, constraints);

    vector<bx_t> cnfs {top};
    for (auto const & constraint : constraints)
        cnfs.push_back(constraint.second->eqvar(constraint.first));

    return and_s(std::move(cnfs));
}

bx_t
Nor::eqvar(var_t const & x) const
{
    // x = ~(a | b | ...) <=> (~x | ~a) & (~x | ~b) & ... & (x | a | b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(~x | ~arg);

    vector<bx_t> lits {x};
    for (bx_t const & arg : args)
        lits.push_back(arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
Or::eqvar(var_t const & x) const
{
    // x = a | b | ... <=> (x | ~a) & (x | ~b) & ... & (~x | a | b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(x | ~arg);

    vector<bx_t> lits {~x};
    for (bx_t const & arg : args)
        lits.push_back(arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
Nand::eqvar(var_t const & x) const
{
    // x = ~(a & b & ...) <=> (x | a) & (x | b) & ... & (~x | ~a | ~b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(x | arg);

    vector<bx_t> lits {~x};
    for (bx_t const & arg : args)
        lits.push_back(~arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
And::eqvar(var_t const & x) const
{
    // x = a & b & ... <=> (~x | a) & (~x | b) & ... & (x | ~a | ~b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(~x | arg);

    vector<bx_t> lits {x};
    for (bx_t const & arg : args)
        lits.push_back(~arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
Xnor::eqvar(var_t const & x) const
{
    vector<vector<bx_t>> stack { vector<bx_t> {x} };

    for (bx_t const & arg : args) {
        vector<vector<bx_t>> temp;

        while (stack.size() > 0) {
            auto lits = stack.back();

            vector<bx_t> fst {lits[0]};
            vector<bx_t> snd {~lits[0]};
            for (auto it = lits.cbegin() + 1; it != lits.cend(); ++it) {
                fst.push_back(*it);
                snd.push_back(*it);
            }
            fst.push_back(arg);
            snd.push_back(~arg);

            temp.push_back(std::move(fst));
            temp.push_back(std::move(snd));

            stack.pop_back();
        }

        std::swap(stack, temp);
    }

    vector<bx_t> clauses;
    while (stack.size() > 0) {
        auto lits = stack.back();
        stack.pop_back();
        clauses.push_back(or_(std::move(lits)));
    }

    return and_s(std::move(clauses));
}

bx_t
Xor::eqvar(var_t const & x) const
{
    vector<vector<bx_t>> stack { vector<bx_t> {~x} };

    for (bx_t const & arg : args) {
        vector<vector<bx_t>> temp;

        while (stack.size() > 0) {
            auto lits = stack.back();

            vector<bx_t> fst {lits[0]};
            vector<bx_t> snd {~lits[0]};
            for (auto it = lits.cbegin() + 1; it != lits.cend(); ++it) {
                fst.push_back(*it);
                snd.push_back(*it);
            }
            fst.push_back(arg);
            snd.push_back(~arg);

            temp.push_back(std::move(fst));
            temp.push_back(std::move(snd));

            stack.pop_back();
        }

        std::swap(stack, temp);
    }

    vector<bx_t> clauses;
    while (stack.size() > 0) {
        auto lits = stack.back();
        stack.pop_back();
        clauses.push_back(or_(std::move(lits)));
    }

    return and_s(std::move(clauses));
}

bx_t
Unequal::eqvar(var_t const & x) const
{
    vector<bx_t> clauses;

    vector<bx_t> lits1 {~x};
    for (bx_t const & arg : args)
        lits1.push_back(arg);
    clauses.push_back(or_(std::move(lits1)));

    vector<bx_t> lits2 {~x};
    for (bx_t const & arg : args)
        lits2.push_back(~arg);
    clauses.push_back(or_(std::move(lits2)));

    for (auto i = 0u; i < args.size(); ++i) {
        for (auto j = i + 1u; j < args.size(); ++j) {
            clauses.push_back(x | ~args[i] | args[j]);
            clauses.push_back(x | args[i] | ~args[j]);
        }
    }

    return and_s(std::move(clauses));
}

bx_t
Equal::eqvar(var_t const & x) const
{
    vector<bx_t> clauses;

    vector<bx_t> lits1 {x};
    for (bx_t const & arg : args)
        lits1.push_back(arg);
    clauses.push_back(or_(std::move(lits1)));

    vector<bx_t> lits2 {x};
    for (bx_t const & arg : args)
        lits2.push_back(~arg);
    clauses.push_back(or_(std::move(lits2)));

    for (auto i = 0u; i < args.size(); ++i) {
        for (auto j = i + 1u; j < args.size(); ++j) {
            clauses.push_back(~x | ~args[i] | args[j]);
            clauses.push_back(~x | args[i] | ~args[j]);
        }
    }

    return and_s(std::move(clauses));
}

bx_t
NotImplies::eqvar(var_t const & x) const
{
    auto p = args[0];
    auto q = args[1];

    return and_s({(~x | p), (~x | ~q), (x | ~p | q)});
}

bx_t
Implies::eqvar(var_t const & x) const
{
    auto p = args[0];
    auto q = args[1];

    return and_s({(x | p), (x | ~q), (~x | ~p | q)});
}

bx_t
NotIfThenElse::eqvar(var_t const & x) const
{
    auto s = args[0];
    auto d1 = args[1];
    auto d0 = args[2];

    return and_s({(~x | ~s | ~d1), (~x | s | ~d0), (x | ~s | d1), (x | s | d0), (x | d1 | d0)});
}

bx_t
IfThenElse::eqvar(var_t const & x) const
{
    auto s = args[0];
    auto d1 = args[1];
    auto d0 = args[2];

    return and_s({(x | ~s | ~d1), (x | s | ~d0), (~x | ~s | d1), (~x | s | d0), (~x | d1 | d0)});
}
<commit_msg>Change std::swap to std::move<commit_after>// Copyright 2016 Chris Drake
//
// 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 <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <boost/optional.hpp>
#include <cryptominisat4/cryptominisat.h>

#include "boolexpr/boolexpr.h"

using namespace boolexpr;

var_t
Operator::to_con1(Context& ctx, string const & auxvarname,
                  uint32_t& index, var2op_t& constraints) const
{
    auto key = ctx.get_var(auxvarname + "_" + std::to_string(index++));
    auto val = to_con2(ctx, auxvarname, index, constraints);

    constraints.insert({key, val});

    return key;
}

op_t
Operator::to_con2(Context& ctx, string const & auxvarname,
                  uint32_t& index, var2op_t& constraints) const
{
    bool found_subop = false;
    vector<bx_t> _args;

    // NOTE: do not use transform, b/c there's mutable state
    for (bx_t const & arg : args) {
        if (IS_OP(arg)) {
            found_subop = true;
            auto subop = std::static_pointer_cast<Operator const>(arg);
            auto x = subop->to_con1(ctx, auxvarname, index, constraints);
            _args.push_back(x);
        }
        else {
            _args.push_back(arg);
        }
    }

    if (found_subop)
        return from_args(std::move(_args));

    return std::static_pointer_cast<Operator const>(shared_from_this());
}

bx_t
Atom::tseytin(Context&, string const &) const
{
    return shared_from_this();
}

bx_t
Operator::tseytin(Context& ctx, string const & auxvarname) const
{
    uint32_t index {0};
    var2op_t constraints;

    auto top = to_con1(ctx, auxvarname, index, constraints);

    vector<bx_t> cnfs {top};
    for (auto const & constraint : constraints)
        cnfs.push_back(constraint.second->eqvar(constraint.first));

    return and_s(std::move(cnfs));
}

bx_t
Nor::eqvar(var_t const & x) const
{
    // x = ~(a | b | ...) <=> (~x | ~a) & (~x | ~b) & ... & (x | a | b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(~x | ~arg);

    vector<bx_t> lits {x};
    for (bx_t const & arg : args)
        lits.push_back(arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
Or::eqvar(var_t const & x) const
{
    // x = a | b | ... <=> (x | ~a) & (x | ~b) & ... & (~x | a | b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(x | ~arg);

    vector<bx_t> lits {~x};
    for (bx_t const & arg : args)
        lits.push_back(arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
Nand::eqvar(var_t const & x) const
{
    // x = ~(a & b & ...) <=> (x | a) & (x | b) & ... & (~x | ~a | ~b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(x | arg);

    vector<bx_t> lits {~x};
    for (bx_t const & arg : args)
        lits.push_back(~arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
And::eqvar(var_t const & x) const
{
    // x = a & b & ... <=> (~x | a) & (~x | b) & ... & (x | ~a | ~b | ...)

    vector<bx_t> clauses;

    for (bx_t const & arg : args)
        clauses.push_back(~x | arg);

    vector<bx_t> lits {x};
    for (bx_t const & arg : args)
        lits.push_back(~arg);

    clauses.push_back(or_(std::move(lits)));

    return and_s(std::move(clauses));
}

bx_t
Xnor::eqvar(var_t const & x) const
{
    vector<vector<bx_t>> stack { vector<bx_t> {x} };

    for (bx_t const & arg : args) {
        vector<vector<bx_t>> temp;

        while (stack.size() > 0) {
            auto lits = stack.back();

            vector<bx_t> fst {lits[0]};
            vector<bx_t> snd {~lits[0]};
            for (auto it = lits.cbegin() + 1; it != lits.cend(); ++it) {
                fst.push_back(*it);
                snd.push_back(*it);
            }
            fst.push_back(arg);
            snd.push_back(~arg);

            temp.push_back(std::move(fst));
            temp.push_back(std::move(snd));

            stack.pop_back();
        }

        stack = std::move(temp);
    }

    vector<bx_t> clauses;
    while (stack.size() > 0) {
        auto lits = stack.back();
        stack.pop_back();
        clauses.push_back(or_(std::move(lits)));
    }

    return and_s(std::move(clauses));
}

bx_t
Xor::eqvar(var_t const & x) const
{
    vector<vector<bx_t>> stack { vector<bx_t> {~x} };

    for (bx_t const & arg : args) {
        vector<vector<bx_t>> temp;

        while (stack.size() > 0) {
            auto lits = stack.back();

            vector<bx_t> fst {lits[0]};
            vector<bx_t> snd {~lits[0]};
            for (auto it = lits.cbegin() + 1; it != lits.cend(); ++it) {
                fst.push_back(*it);
                snd.push_back(*it);
            }
            fst.push_back(arg);
            snd.push_back(~arg);

            temp.push_back(std::move(fst));
            temp.push_back(std::move(snd));

            stack.pop_back();
        }

        stack = std::move(temp);
    }

    vector<bx_t> clauses;
    while (stack.size() > 0) {
        auto lits = stack.back();
        stack.pop_back();
        clauses.push_back(or_(std::move(lits)));
    }

    return and_s(std::move(clauses));
}

bx_t
Unequal::eqvar(var_t const & x) const
{
    vector<bx_t> clauses;

    vector<bx_t> lits1 {~x};
    for (bx_t const & arg : args)
        lits1.push_back(arg);
    clauses.push_back(or_(std::move(lits1)));

    vector<bx_t> lits2 {~x};
    for (bx_t const & arg : args)
        lits2.push_back(~arg);
    clauses.push_back(or_(std::move(lits2)));

    for (auto i = 0u; i < args.size(); ++i) {
        for (auto j = i + 1u; j < args.size(); ++j) {
            clauses.push_back(x | ~args[i] | args[j]);
            clauses.push_back(x | args[i] | ~args[j]);
        }
    }

    return and_s(std::move(clauses));
}

bx_t
Equal::eqvar(var_t const & x) const
{
    vector<bx_t> clauses;

    vector<bx_t> lits1 {x};
    for (bx_t const & arg : args)
        lits1.push_back(arg);
    clauses.push_back(or_(std::move(lits1)));

    vector<bx_t> lits2 {x};
    for (bx_t const & arg : args)
        lits2.push_back(~arg);
    clauses.push_back(or_(std::move(lits2)));

    for (auto i = 0u; i < args.size(); ++i) {
        for (auto j = i + 1u; j < args.size(); ++j) {
            clauses.push_back(~x | ~args[i] | args[j]);
            clauses.push_back(~x | args[i] | ~args[j]);
        }
    }

    return and_s(std::move(clauses));
}

bx_t
NotImplies::eqvar(var_t const & x) const
{
    auto p = args[0];
    auto q = args[1];

    return and_s({(~x | p), (~x | ~q), (x | ~p | q)});
}

bx_t
Implies::eqvar(var_t const & x) const
{
    auto p = args[0];
    auto q = args[1];

    return and_s({(x | p), (x | ~q), (~x | ~p | q)});
}

bx_t
NotIfThenElse::eqvar(var_t const & x) const
{
    auto s = args[0];
    auto d1 = args[1];
    auto d0 = args[2];

    return and_s({(~x | ~s | ~d1), (~x | s | ~d0), (x | ~s | d1), (x | s | d0), (x | d1 | d0)});
}

bx_t
IfThenElse::eqvar(var_t const & x) const
{
    auto s = args[0];
    auto d1 = args[1];
    auto d0 = args[2];

    return and_s({(x | ~s | ~d1), (x | s | ~d0), (~x | ~s | d1), (~x | s | d0), (~x | d1 | d0)});
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, MassaRoddel, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"

#include "libtorrent/extensions/ut_pex.hpp"

namespace libtorrent { namespace
{
	const char extension_name[] = "ut_pex";

	enum
	{
		extension_index = 1,
		max_peer_entries = 100
	};

	bool send_peer(peer_connection const& p)
	{
		// don't send out peers that we haven't connected to
		// (that have connected to us)
		if (!p.is_local()) return false;
		// don't send out peers that we haven't successfully connected to
		if (p.is_connecting()) return false;
		return true;
	}

	struct ut_pex_plugin: torrent_plugin
	{
		ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}

		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);

		std::vector<char>& get_ut_pex_msg()
		{
			return m_ut_pex_msg;
		}

		// the second tick of the torrent
		// each minute the new lists of "added" + "added.f" and "dropped"
		// are calculated here and the pex message is created
		// each peer connection will use this message
		// max_peer_entries limits the packet size
		virtual void tick()
		{
			if (++m_1_minute < 60) return;

			m_1_minute = 0;

			entry pex;
			std::string& pla = pex["added"].string();
			std::string& pld = pex["dropped"].string();
			std::string& plf = pex["added.f"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& pld6 = pex["dropped6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> pld_out(pld);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> pld6_out(pld6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			std::set<tcp::endpoint> dropped;
			m_old_peers.swap(dropped);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				tcp::endpoint const& remote = peer->remote();
				m_old_peers.insert(remote);

				std::set<tcp::endpoint>::iterator di = dropped.find(remote);
				if (di == dropped.end())
				{
					// don't write too big of a package
					if (num_added >= max_peer_entries) break;

					// only send proper bittorrent peers
					bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
					if (!p) continue;

					// no supported flags to set yet
					// 0x01 - peer supports encryption
					// 0x02 - peer is a seed
					int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
					flags |= p->supports_encryption() ? 1 : 0;
#endif
					// i->first was added since the last time
					if (remote.address().is_v4())
					{
						detail::write_endpoint(remote, pla_out);
						detail::write_uint8(flags, plf_out);
					}
					else
					{
						detail::write_endpoint(remote, pla6_out);
						detail::write_uint8(flags, plf6_out);
					}
					++num_added;
				}
				else
				{
					// this was in the previous message
					// so, it wasn't dropped
					dropped.erase(di);
				}
			}

			for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
				, end(dropped.end()); i != end; ++i)
			{
				if (i->address().is_v4())
					detail::write_endpoint(*i, pld_out);
				else
					detail::write_endpoint(*i, pld6_out);
			}

			m_ut_pex_msg.clear();
			bencode(std::back_inserter(m_ut_pex_msg), pex);
		}

	private:
		torrent& m_torrent;

		std::set<tcp::endpoint> m_old_peers;
		int m_1_minute;
		std::vector<char> m_ut_pex_msg;
	};

	struct ut_pex_peer_plugin : peer_plugin
	{
		ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
			: m_torrent(t)
			, m_pc(pc)
			, m_tp(tp)
			, m_1_minute(55)
			, m_message_index(0)
			, m_first_time(true)
		{}

		virtual void add_handshake(entry& h)
		{
			entry& messages = h["m"];
			messages[extension_name] = extension_index;
		}

		virtual bool on_extension_handshake(entry const& h)
		{
			entry const& messages = h["m"];

			if (entry const* index = messages.find_key(extension_name))
			{
				m_message_index = index->integer();
				return true;
			}
			else
			{
				m_message_index = 0;
				return false;
			}
		}

		virtual bool on_extended(int length, int msg, buffer::const_interval body)
		{
			if (msg != extension_index) return false;
			if (m_message_index == 0) return false;

			if (length > 500 * 1024)
				throw protocol_error("uT peer exchange message larger than 500 kB");

			if (body.left() < length) return true;

			try
			{
				entry pex_msg = bdecode(body.begin, body.end);
				std::string const& peers = pex_msg["added"].string();
				std::string const& peer_flags = pex_msg["added.f"].string();

				int num_peers = peers.length() / 6;
				char const* in = peers.c_str();
				char const* fin = peer_flags.c_str();

				if (int(peer_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}

				if (entry const* p6 = pex_msg.find_key("added6"))
				{
					std::string const& peers6 = p6->string();
					std::string const& peer6_flags = pex_msg["added6.f"].string();

					int num_peers = peers6.length() / 18;
					char const* in = peers6.c_str();
					char const* fin = peer6_flags.c_str();

					if (int(peer6_flags.size()) != num_peers)
						return true;

					peer_id pid(0);
					policy& p = m_torrent.get_policy();
					for (int i = 0; i < num_peers; ++i)
					{
						tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
						char flags = detail::read_uint8(fin);
						p.peer_from_tracker(adr, pid, peer_info::pex, flags);
					}
				}
			}
			catch (std::exception&)
			{
				throw protocol_error("invalid uT peer exchange message");
			}
			return true;
		}

		// the peers second tick
		// every minute we send a pex message
		virtual void tick()
		{
			if (!m_message_index) return;	// no handshake yet
			if (++m_1_minute <= 60) return;

			if (m_first_time)
			{
				send_ut_peer_list();
				m_first_time = false;
			}
			else
			{
				send_ut_peer_diff();
			}
			m_1_minute = 0;
		}

	private:

		void send_ut_peer_diff()
		{
			std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		void send_ut_peer_list()
		{
			entry pex;
			// leave the dropped string empty
			pex["dropped"].string();
			std::string& pla = pex["added"].string();
			std::string& plf = pex["added.f"].string();
			pex["dropped6"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				// don't write too big of a package
				if (num_added >= max_peer_entries) break;

				// only send proper bittorrent peers
				bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
				if (!p) continue;

				// no supported flags to set yet
				// 0x01 - peer supports encryption
				// 0x02 - peer is a seed
				int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
				flags |= p->supports_encryption() ? 1 : 0;
#endif
				tcp::endpoint const& remote = peer->remote();
				// i->first was added since the last time
				if (remote.address().is_v4())
				{
					detail::write_endpoint(remote, pla_out);
					detail::write_uint8(flags, plf_out);
				}
				else
				{
					detail::write_endpoint(remote, pla6_out);
					detail::write_uint8(flags, plf6_out);
				}
				++num_added;
			}
			std::vector<char> pex_msg;
			bencode(std::back_inserter(pex_msg), pex);

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		torrent& m_torrent;
		peer_connection& m_pc;
		ut_pex_plugin& m_tp;
		int m_1_minute;
		int m_message_index;

		// this is initialized to true, and set to
		// false after the first pex message has been sent.
		// it is used to know if a diff message or a full
		// message should be sent.
		bool m_first_time;
	};

	boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
	{
		bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
		if (!c) return boost::shared_ptr<peer_plugin>();
		return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
			, *pc, *this));
	}
}}

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
	{
		if (t->torrent_file().priv())
		{
			return boost::shared_ptr<torrent_plugin>();
		}
		return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
	}

}

<commit_msg>made ut_pex not rely on exceptions<commit_after>/*

Copyright (c) 2006, MassaRoddel, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"

#include "libtorrent/extensions/ut_pex.hpp"

namespace libtorrent { namespace
{
	const char extension_name[] = "ut_pex";

	enum
	{
		extension_index = 1,
		max_peer_entries = 100
	};

	bool send_peer(peer_connection const& p)
	{
		// don't send out peers that we haven't connected to
		// (that have connected to us)
		if (!p.is_local()) return false;
		// don't send out peers that we haven't successfully connected to
		if (p.is_connecting()) return false;
		return true;
	}

	struct ut_pex_plugin: torrent_plugin
	{
		ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}

		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);

		std::vector<char>& get_ut_pex_msg()
		{
			return m_ut_pex_msg;
		}

		// the second tick of the torrent
		// each minute the new lists of "added" + "added.f" and "dropped"
		// are calculated here and the pex message is created
		// each peer connection will use this message
		// max_peer_entries limits the packet size
		virtual void tick()
		{
			if (++m_1_minute < 60) return;

			m_1_minute = 0;

			entry pex;
			std::string& pla = pex["added"].string();
			std::string& pld = pex["dropped"].string();
			std::string& plf = pex["added.f"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& pld6 = pex["dropped6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> pld_out(pld);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> pld6_out(pld6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			std::set<tcp::endpoint> dropped;
			m_old_peers.swap(dropped);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
					peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				tcp::endpoint const& remote = peer->remote();
				m_old_peers.insert(remote);

				std::set<tcp::endpoint>::iterator di = dropped.find(remote);
				if (di == dropped.end())
				{
					// don't write too big of a package
					if (num_added >= max_peer_entries) break;

					// only send proper bittorrent peers
					bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
					if (!p) continue;

					// no supported flags to set yet
					// 0x01 - peer supports encryption
					// 0x02 - peer is a seed
					int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
					flags |= p->supports_encryption() ? 1 : 0;
#endif
					// i->first was added since the last time
					if (remote.address().is_v4())
					{
						detail::write_endpoint(remote, pla_out);
						detail::write_uint8(flags, plf_out);
					}
					else
					{
						detail::write_endpoint(remote, pla6_out);
						detail::write_uint8(flags, plf6_out);
					}
					++num_added;
				}
				else
				{
					// this was in the previous message
					// so, it wasn't dropped
					dropped.erase(di);
				}
			}

			for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
				, end(dropped.end()); i != end; ++i)
			{
				if (i->address().is_v4())
					detail::write_endpoint(*i, pld_out);
				else
					detail::write_endpoint(*i, pld6_out);
			}

			m_ut_pex_msg.clear();
			bencode(std::back_inserter(m_ut_pex_msg), pex);
		}

	private:
		torrent& m_torrent;

		std::set<tcp::endpoint> m_old_peers;
		int m_1_minute;
		std::vector<char> m_ut_pex_msg;
	};

	struct ut_pex_peer_plugin : peer_plugin
	{
		ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
			: m_torrent(t)
			, m_pc(pc)
			, m_tp(tp)
			, m_1_minute(55)
			, m_message_index(0)
			, m_first_time(true)
		{}

		virtual void add_handshake(entry& h)
		{
			entry& messages = h["m"];
			messages[extension_name] = extension_index;
		}

		virtual bool on_extension_handshake(entry const& h)
		{
			m_message_index = 0;
			entry const* messages = h.find_key("m");
			if (!messages || messages->type() != entry::dictionary_t) return false;

			entry const* index = messages->find_key(extension_name);
			if (!index || index->type() != entry::int_t) return false;

			m_message_index = index->integer();
			return true;
		}

		virtual bool on_extended(int length, int msg, buffer::const_interval body)
		{
			if (msg != extension_index) return false;
			if (m_message_index == 0) return false;

			if (length > 500 * 1024)
				throw protocol_error("uT peer exchange message larger than 500 kB");

			if (body.left() < length) return true;

			entry pex_msg = bdecode(body.begin, body.end);

			entry const* p = pex_msg.find_key("added");
			entry const* pf = pex_msg.find_key("added.f");

			if (p != 0 && pf != 0 && p->type() == entry::string_t && pf->type() == entry::string_t)
			{
				std::string const& peers = p->string();
				std::string const& peer_flags = pf->string();

				int num_peers = peers.length() / 6;
				char const* in = peers.c_str();
				char const* fin = peer_flags.c_str();

				if (int(peer_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}
			}

			entry const* p6 = pex_msg.find_key("added6");
			entry const* p6f = pex_msg.find_key("added6.f");
			if (p6 && p6f && p6->type() == entry::string_t && p6f->type() == entry::string_t)
			{
				std::string const& peers6 = p6->string();
				std::string const& peer6_flags = p6f->string();

				int num_peers = peers6.length() / 18;
				char const* in = peers6.c_str();
				char const* fin = peer6_flags.c_str();

				if (int(peer6_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}
			}
			return true;
		}

		// the peers second tick
		// every minute we send a pex message
		virtual void tick()
		{
			if (!m_message_index) return;	// no handshake yet
			if (++m_1_minute <= 60) return;

			if (m_first_time)
			{
				send_ut_peer_list();
				m_first_time = false;
			}
			else
			{
				send_ut_peer_diff();
			}
			m_1_minute = 0;
		}

	private:

		void send_ut_peer_diff()
		{
			std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		void send_ut_peer_list()
		{
			entry pex;
			// leave the dropped string empty
			pex["dropped"].string();
			std::string& pla = pex["added"].string();
			std::string& plf = pex["added.f"].string();
			pex["dropped6"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				// don't write too big of a package
				if (num_added >= max_peer_entries) break;

				// only send proper bittorrent peers
				bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
				if (!p) continue;

				// no supported flags to set yet
				// 0x01 - peer supports encryption
				// 0x02 - peer is a seed
				int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
				flags |= p->supports_encryption() ? 1 : 0;
#endif
				tcp::endpoint const& remote = peer->remote();
				// i->first was added since the last time
				if (remote.address().is_v4())
				{
					detail::write_endpoint(remote, pla_out);
					detail::write_uint8(flags, plf_out);
				}
				else
				{
					detail::write_endpoint(remote, pla6_out);
					detail::write_uint8(flags, plf6_out);
				}
				++num_added;
			}
			std::vector<char> pex_msg;
			bencode(std::back_inserter(pex_msg), pex);

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		torrent& m_torrent;
		peer_connection& m_pc;
		ut_pex_plugin& m_tp;
		int m_1_minute;
		int m_message_index;

		// this is initialized to true, and set to
		// false after the first pex message has been sent.
		// it is used to know if a diff message or a full
		// message should be sent.
		bool m_first_time;
	};

	boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
	{
		bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
		if (!c) return boost::shared_ptr<peer_plugin>();
		return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
			, *pc, *this));
	}
}}

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
	{
		if (t->torrent_file().priv())
		{
			return boost::shared_ptr<torrent_plugin>();
		}
		return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
	}

}

<|endoftext|>