<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkRefCnt.h"
#include "include/core/SkString.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/effects/SkColorMatrix.h"
#include "include/private/SkColorData.h"
#include "include/private/SkNx.h"
#include "src/core/SkColorFilter_Matrix.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"

static uint16_t ComputeFlags(const float matrix[20]) {
    const float* srcA = matrix + 15;

    return SkScalarNearlyZero (srcA[0])
        && SkScalarNearlyZero (srcA[1])
        && SkScalarNearlyZero (srcA[2])
        && SkScalarNearlyEqual(srcA[3], 1)
        && SkScalarNearlyZero (srcA[4])
            ? SkColorFilter::kAlphaUnchanged_Flag : 0;
}

SkColorFilter_Matrix::SkColorFilter_Matrix(const float array[20], Domain domain)
    : fFlags(ComputeFlags(array))
    , fDomain(domain) {
    memcpy(fMatrix, array, 20 * sizeof(float));
}

uint32_t SkColorFilter_Matrix::getFlags() const {
    return this->INHERITED::getFlags() | fFlags;
}

void SkColorFilter_Matrix::flatten(SkWriteBuffer& buffer) const {
    SkASSERT(sizeof(fMatrix)/sizeof(float) == 20);
    buffer.writeScalarArray(fMatrix, 20);

    // RGBA flag
    buffer.writeBool(fDomain == Domain::kRGBA);
}

sk_sp<SkFlattenable> SkColorFilter_Matrix::CreateProc(SkReadBuffer& buffer) {
    float matrix[20];
    if (!buffer.readScalarArray(matrix, 20)) {
        return nullptr;
    }

    auto   is_rgba = buffer.isVersionLT(SkPicturePriv::kMatrixColorFilterDomain_Version) ||
                     buffer.readBool();
    return is_rgba ? SkColorFilters::Matrix(matrix)
                   : SkColorFilters::HSLAMatrix(matrix);
}

bool SkColorFilter_Matrix::onAsAColorMatrix(float matrix[20]) const {
    if (matrix) {
        memcpy(matrix, fMatrix, 20 * sizeof(float));
    }
    return true;
}

bool SkColorFilter_Matrix::onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
    const bool willStayOpaque = shaderIsOpaque && (fFlags & kAlphaUnchanged_Flag),
                         hsla = fDomain == Domain::kHSLA;

    SkRasterPipeline* p = rec.fPipeline;
    if (!shaderIsOpaque) { p->append(SkRasterPipeline::unpremul); }
    if (           hsla) { p->append(SkRasterPipeline::rgb_to_hsl); }
    if (           true) { p->append(SkRasterPipeline::matrix_4x5, fMatrix); }
    if (           hsla) { p->append(SkRasterPipeline::hsl_to_rgb); }
    if (           true) { p->append(SkRasterPipeline::clamp_0); }
    if (           true) { p->append(SkRasterPipeline::clamp_1); }
    if (!willStayOpaque) { p->append(SkRasterPipeline::premul); }
    return true;
}

bool SkColorFilter_Matrix::program(skvm::Builder* p,
                                   SkColorSpace* /*dstCS*/,
                                   skvm::Uniforms* uniforms,
                                   skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const {
    // TODO: specialize generated code on the 0/1 values of fMatrix?
    if (fDomain == Domain::kRGBA) {
        // Convert to [0,1] floats.
        skvm::F32 R = p->mul(p->to_f32(*r), p->splat(1/255.0f)),
                  G = p->mul(p->to_f32(*g), p->splat(1/255.0f)),
                  B = p->mul(p->to_f32(*b), p->splat(1/255.0f)),
                  A = p->mul(p->to_f32(*a), p->splat(1/255.0f));

        // Unpremul.
        skvm::F32 invA = p->select(p->eq(A, p->splat(0.0f)), p->splat(0.0f)
                                                           , p->div(p->splat(1.0f), A));
        R = p->mul(R, invA);
        G = p->mul(G, invA);
        B = p->mul(B, invA);

        // Apply matrix.
        skvm::Builder::Uniform u = uniforms->pushF(fMatrix, 20);
        auto m = [&](int i) { return p->bit_cast(p->uniform32(u.ptr, u.offset + 4*i)); };

        skvm::F32 rgba[4];
        for (int j = 0; j < 4; j++) {
            rgba[j] = p->mad(m(0+j*5), R,
                      p->mad(m(1+j*5), G,
                      p->mad(m(2+j*5), B,
                      p->mad(m(3+j*5), A,
                             m(4+j*5)))));
        }

        // Clamp back to bytes.
        R = p->mad(rgba[0], p->splat(255.0f), p->splat(0.5f));
        G = p->mad(rgba[1], p->splat(255.0f), p->splat(0.5f));
        B = p->mad(rgba[2], p->splat(255.0f), p->splat(0.5f));
        A = p->mad(rgba[3], p->splat(255.0f), p->splat(0.5f));

        *r = p->max(p->splat(0), p->min(p->to_i32(R), p->splat(255)));
        *g = p->max(p->splat(0), p->min(p->to_i32(G), p->splat(255)));
        *b = p->max(p->splat(0), p->min(p->to_i32(B), p->splat(255)));
        *a = p->max(p->splat(0), p->min(p->to_i32(A), p->splat(255)));

        // Premul.
        *r = p->scale_unorm8(*r, *a);
        *g = p->scale_unorm8(*g, *a);
        *b = p->scale_unorm8(*b, *a);
        return true;
    }
    return false;
}

#if SK_SUPPORT_GPU
#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
#include "src/gpu/effects/generated/GrHSLToRGBFilterEffect.h"
#include "src/gpu/effects/generated/GrRGBToHSLFilterEffect.h"
std::unique_ptr<GrFragmentProcessor> SkColorFilter_Matrix::asFragmentProcessor(
        GrRecordingContext*, const GrColorInfo&) const {
    switch (fDomain) {
        case Domain::kRGBA:
            return GrColorMatrixFragmentProcessor::Make(fMatrix,
                                                        /* premulInput = */    true,
                                                        /* clampRGBOutput = */ true,
                                                        /* premulOutput = */   true);
        case Domain::kHSLA: {
            std::unique_ptr<GrFragmentProcessor> series[] = {
                GrRGBToHSLFilterEffect::Make(),
                GrColorMatrixFragmentProcessor::Make(fMatrix,
                                                     /* premulInput = */    false,
                                                     /* clampRGBOutput = */ false,
                                                     /* premulOutput = */   false),
                GrHSLToRGBFilterEffect::Make(),
            };
            return GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series));
        }
    }

    SkUNREACHABLE;
}

#endif

///////////////////////////////////////////////////////////////////////////////

static sk_sp<SkColorFilter> MakeMatrix(const float array[20],
                                       SkColorFilter_Matrix::Domain domain) {
    return sk_floats_are_finite(array, 20)
        ? sk_make_sp<SkColorFilter_Matrix>(array, domain)
        : nullptr;
}

sk_sp<SkColorFilter> SkColorFilters::Matrix(const float array[20]) {
    return MakeMatrix(array, SkColorFilter_Matrix::Domain::kRGBA);
}

sk_sp<SkColorFilter> SkColorFilters::Matrix(const SkColorMatrix& cm) {
    return MakeMatrix(cm.fMat.data(), SkColorFilter_Matrix::Domain::kRGBA);
}

sk_sp<SkColorFilter> SkColorFilters::HSLAMatrix(const float array[20]) {
    return MakeMatrix(array, SkColorFilter_Matrix::Domain::kHSLA);
}

void SkColorFilter_Matrix::RegisterFlattenables() {
    SK_REGISTER_FLATTENABLE(SkColorFilter_Matrix);

    // This subclass was removed 4/2019
    SkFlattenable::Register("SkColorMatrixFilterRowMajor255",
                            [](SkReadBuffer& buffer) -> sk_sp<SkFlattenable> {
        float matrix[20];
        if (buffer.readScalarArray(matrix, 20)) {
            matrix[ 4] *= (1.0f/255);
            matrix[ 9] *= (1.0f/255);
            matrix[14] *= (1.0f/255);
            matrix[19] *= (1.0f/255);
            return SkColorFilters::Matrix(matrix);
        }
        return nullptr;
    });
}
<commit_msg>unnest matrix multiply<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkRefCnt.h"
#include "include/core/SkString.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/effects/SkColorMatrix.h"
#include "include/private/SkColorData.h"
#include "include/private/SkNx.h"
#include "src/core/SkColorFilter_Matrix.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"

static uint16_t ComputeFlags(const float matrix[20]) {
    const float* srcA = matrix + 15;

    return SkScalarNearlyZero (srcA[0])
        && SkScalarNearlyZero (srcA[1])
        && SkScalarNearlyZero (srcA[2])
        && SkScalarNearlyEqual(srcA[3], 1)
        && SkScalarNearlyZero (srcA[4])
            ? SkColorFilter::kAlphaUnchanged_Flag : 0;
}

SkColorFilter_Matrix::SkColorFilter_Matrix(const float array[20], Domain domain)
    : fFlags(ComputeFlags(array))
    , fDomain(domain) {
    memcpy(fMatrix, array, 20 * sizeof(float));
}

uint32_t SkColorFilter_Matrix::getFlags() const {
    return this->INHERITED::getFlags() | fFlags;
}

void SkColorFilter_Matrix::flatten(SkWriteBuffer& buffer) const {
    SkASSERT(sizeof(fMatrix)/sizeof(float) == 20);
    buffer.writeScalarArray(fMatrix, 20);

    // RGBA flag
    buffer.writeBool(fDomain == Domain::kRGBA);
}

sk_sp<SkFlattenable> SkColorFilter_Matrix::CreateProc(SkReadBuffer& buffer) {
    float matrix[20];
    if (!buffer.readScalarArray(matrix, 20)) {
        return nullptr;
    }

    auto   is_rgba = buffer.isVersionLT(SkPicturePriv::kMatrixColorFilterDomain_Version) ||
                     buffer.readBool();
    return is_rgba ? SkColorFilters::Matrix(matrix)
                   : SkColorFilters::HSLAMatrix(matrix);
}

bool SkColorFilter_Matrix::onAsAColorMatrix(float matrix[20]) const {
    if (matrix) {
        memcpy(matrix, fMatrix, 20 * sizeof(float));
    }
    return true;
}

bool SkColorFilter_Matrix::onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
    const bool willStayOpaque = shaderIsOpaque && (fFlags & kAlphaUnchanged_Flag),
                         hsla = fDomain == Domain::kHSLA;

    SkRasterPipeline* p = rec.fPipeline;
    if (!shaderIsOpaque) { p->append(SkRasterPipeline::unpremul); }
    if (           hsla) { p->append(SkRasterPipeline::rgb_to_hsl); }
    if (           true) { p->append(SkRasterPipeline::matrix_4x5, fMatrix); }
    if (           hsla) { p->append(SkRasterPipeline::hsl_to_rgb); }
    if (           true) { p->append(SkRasterPipeline::clamp_0); }
    if (           true) { p->append(SkRasterPipeline::clamp_1); }
    if (!willStayOpaque) { p->append(SkRasterPipeline::premul); }
    return true;
}

bool SkColorFilter_Matrix::program(skvm::Builder* p,
                                   SkColorSpace* /*dstCS*/,
                                   skvm::Uniforms* uniforms,
                                   skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const {
    // TODO: specialize generated code on the 0/1 values of fMatrix?
    if (fDomain == Domain::kRGBA) {
        // Convert to [0,1] floats.
        skvm::F32 R = p->mul(p->to_f32(*r), p->splat(1/255.0f)),
                  G = p->mul(p->to_f32(*g), p->splat(1/255.0f)),
                  B = p->mul(p->to_f32(*b), p->splat(1/255.0f)),
                  A = p->mul(p->to_f32(*a), p->splat(1/255.0f));

        // Unpremul.
        skvm::F32 invA = p->select(p->eq(A, p->splat(0.0f)), p->splat(0.0f)
                                                           , p->div(p->splat(1.0f), A));
        R = p->mul(R, invA);
        G = p->mul(G, invA);
        B = p->mul(B, invA);

        // Apply matrix.
        skvm::Builder::Uniform u = uniforms->pushF(fMatrix, 20);
        auto m = [&](int i) { return p->bit_cast(p->uniform32(u.ptr, u.offset + 4*i)); };

        skvm::F32 rgba[4];
        for (int j = 0; j < 4; j++) {
            rgba[j] =        m(4+j*5);
            rgba[j] = p->mad(m(3+j*5), A, rgba[j]);
            rgba[j] = p->mad(m(2+j*5), B, rgba[j]);
            rgba[j] = p->mad(m(1+j*5), G, rgba[j]);
            rgba[j] = p->mad(m(0+j*5), R, rgba[j]);
        }

        // Clamp back to bytes.
        R = p->mad(rgba[0], p->splat(255.0f), p->splat(0.5f));
        G = p->mad(rgba[1], p->splat(255.0f), p->splat(0.5f));
        B = p->mad(rgba[2], p->splat(255.0f), p->splat(0.5f));
        A = p->mad(rgba[3], p->splat(255.0f), p->splat(0.5f));

        *r = p->max(p->splat(0), p->min(p->to_i32(R), p->splat(255)));
        *g = p->max(p->splat(0), p->min(p->to_i32(G), p->splat(255)));
        *b = p->max(p->splat(0), p->min(p->to_i32(B), p->splat(255)));
        *a = p->max(p->splat(0), p->min(p->to_i32(A), p->splat(255)));

        // Premul.
        *r = p->scale_unorm8(*r, *a);
        *g = p->scale_unorm8(*g, *a);
        *b = p->scale_unorm8(*b, *a);
        return true;
    }
    return false;
}

#if SK_SUPPORT_GPU
#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
#include "src/gpu/effects/generated/GrHSLToRGBFilterEffect.h"
#include "src/gpu/effects/generated/GrRGBToHSLFilterEffect.h"
std::unique_ptr<GrFragmentProcessor> SkColorFilter_Matrix::asFragmentProcessor(
        GrRecordingContext*, const GrColorInfo&) const {
    switch (fDomain) {
        case Domain::kRGBA:
            return GrColorMatrixFragmentProcessor::Make(fMatrix,
                                                        /* premulInput = */    true,
                                                        /* clampRGBOutput = */ true,
                                                        /* premulOutput = */   true);
        case Domain::kHSLA: {
            std::unique_ptr<GrFragmentProcessor> series[] = {
                GrRGBToHSLFilterEffect::Make(),
                GrColorMatrixFragmentProcessor::Make(fMatrix,
                                                     /* premulInput = */    false,
                                                     /* clampRGBOutput = */ false,
                                                     /* premulOutput = */   false),
                GrHSLToRGBFilterEffect::Make(),
            };
            return GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series));
        }
    }

    SkUNREACHABLE;
}

#endif

///////////////////////////////////////////////////////////////////////////////

static sk_sp<SkColorFilter> MakeMatrix(const float array[20],
                                       SkColorFilter_Matrix::Domain domain) {
    return sk_floats_are_finite(array, 20)
        ? sk_make_sp<SkColorFilter_Matrix>(array, domain)
        : nullptr;
}

sk_sp<SkColorFilter> SkColorFilters::Matrix(const float array[20]) {
    return MakeMatrix(array, SkColorFilter_Matrix::Domain::kRGBA);
}

sk_sp<SkColorFilter> SkColorFilters::Matrix(const SkColorMatrix& cm) {
    return MakeMatrix(cm.fMat.data(), SkColorFilter_Matrix::Domain::kRGBA);
}

sk_sp<SkColorFilter> SkColorFilters::HSLAMatrix(const float array[20]) {
    return MakeMatrix(array, SkColorFilter_Matrix::Domain::kHSLA);
}

void SkColorFilter_Matrix::RegisterFlattenables() {
    SK_REGISTER_FLATTENABLE(SkColorFilter_Matrix);

    // This subclass was removed 4/2019
    SkFlattenable::Register("SkColorMatrixFilterRowMajor255",
                            [](SkReadBuffer& buffer) -> sk_sp<SkFlattenable> {
        float matrix[20];
        if (buffer.readScalarArray(matrix, 20)) {
            matrix[ 4] *= (1.0f/255);
            matrix[ 9] *= (1.0f/255);
            matrix[14] *= (1.0f/255);
            matrix[19] *= (1.0f/255);
            return SkColorFilters::Matrix(matrix);
        }
        return nullptr;
    });
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
***************************************************************************/
///////////////////////////////////////////////////////////////////////////
//  Class to generate decays of particles generated by a                 //
//  previous generator. It works as a generator, but pratically it       //
//  performs only decays. It works with this scheme: first loops over    //
//  particles on the stack, selects those to be decayed, decays them     //
//  and then pushes the decay products on the stack.                     //
//                                                                       //
//  Giuseppe E. Bruno            &    Fiorella Fionda                    //
//  (Giuseppe.Bruno@ba.infn.it)       (Fiorella.Fionda@ba.infn.it)       //
///////////////////////////////////////////////////////////////////////////

#include "AliStack.h"
#include "AliGenEvtGen.h"
#include "AliRun.h"
#include "AliLog.h"
#include <TParticle.h>

ClassImp(AliGenEvtGen)
///////////////////////////////////////////////////////////////////////////
AliGenEvtGen::AliGenEvtGen():
  fStack(0x0),
  fDecayer(0x0),
  fForceDecay(kAll),
  fSwitchOff(kBeautyPart),
  fUserDecay(kFALSE),
  fUserDecayTablePath(0x0)
  {
  //
  // Default Construction
  //
  }
///////////////////////////////////////////////////////////////////////////////////////////
AliGenEvtGen::~AliGenEvtGen()
  {
  //
  // Standard Destructor
  //
  if(fStack) {delete fStack;}
  fStack = 0;
  if(fDecayer) {delete fDecayer;}
  fDecayer = 0;
  if(fUserDecayTablePath) {delete fUserDecayTablePath;}
  fUserDecayTablePath = 0;
  }
///////////////////////////////////////////////////////////////////////////////////////////

void AliGenEvtGen::Init()
  {
  //
  // Standard AliGenerator Initializer - no input
  // 1) initialize EvtGen with default decay and particle table
  // 2) set the decay mode to force particle
  // 3) set a user decay table if defined
  //
  if(fDecayer)
  {
  AliWarning("AliGenEvtGen already initialized!!!");
  return;
  }
  fDecayer = new AliDecayerEvtGen();
  fDecayer->Init(); //read the default decay table DECAY.DEC and particle table

  //if is set a decay mode: default decay mode is kAll
  fDecayer->SetForceDecay(fForceDecay);
  fDecayer->ForceDecay();

  //if is defined a user decay table
  if(fUserDecay)
    {
    fDecayer->SetDecayTablePath(fUserDecayTablePath);
    fDecayer->ReadDecayTable();
    }
  }

/////////////////////////////////////////////////////////////////////////////////////////////
void AliGenEvtGen::Generate()
  {
  //
  //Generate method - Input none - Output none
  //For each event:
  //1)return the stack of the previous generator and select particles to be decayed by EvtGen
  //2)decay particles selected and put the decay products on the stack
  //
  //
  Float_t polar[3]= {0,0,0};  // Polarisation of daughter particles
  Float_t origin0[3];         // Origin of the parent particle
  Float_t pc[3], och[3]; // Momentum and origin of the children particles from EvtGen
  Int_t nt;
  Float_t tof;
  Int_t nPrimsPythia;
  TLorentzVector *mom=new TLorentzVector();
  static TClonesArray *particles;
  if(!particles) particles = new TClonesArray("TParticle",1000);
  fStack = AliRunLoader::Instance()->Stack();
  if(!fStack) {Info("Generate","Error: No stack found!"); return;}
  nPrimsPythia = fStack->GetNprimary();
  AliDebug(1,Form("nPrimsPythia = %d \n",nPrimsPythia));
  for (Int_t iTrack = 0; iTrack < nPrimsPythia; ++iTrack) {
  TParticle *part = fStack->Particle(iTrack);
  Int_t pdg=part->GetPdgCode();

  AliDebug(1,Form("GetFlavour = %d e pdg = %d \n",GetFlavour(pdg),pdg));

  switch(fSwitchOff)
  {
  case kAllPart:
  break;
  case kBeautyPart:
  if(GetFlavour(pdg)!=5) continue;
  break;
  case kCharmPart:
  if(GetFlavour(pdg)!=4) continue;
  break;
  }

  //check if particle is already decayed by Pythia
  if(part->GetStatusCode() != 1 || part->GetNDaughters()>0)
    {
    AliDebug(1,Form("Attention: particle %d is already decayed by Pythia!",pdg));
    continue;
    }

  part->SetStatusCode(11); //Set particle as decayed : change the status code
  part->SetBit(kDoneBit);
  part->ResetBit(kTransportBit);

  mom->SetPxPyPzE(part->Px(),part->Py(),part->Pz(),part->Energy());
  Int_t np;

   do{
     fDecayer->Decay(part->GetPdgCode(),mom);
     np = fDecayer->ImportParticles(particles);
     }while(np<0);

  Int_t* trackIt    = new Int_t[np];
  Int_t* pParent   = new Int_t[np];
  AliDebug(1,Form("np = %d \n",np));

  for (int i = 0; i < np; i++) {
             pParent[i]   = -1;
             trackIt[i]   =  0;
         }
  //select trackable particle
  if (np >1) {
    TParticle* iparticle =  0;//(TParticle *) particles->At(0);//parent particle
   for (int i = 1; i<np ; i++) {
     iparticle = (TParticle*) particles->At(i);
     Int_t ks = iparticle->GetStatusCode();

     //track last decay products
     if(ks==1) trackIt[i]=1;

     }//decay particles loop

  }// if decay products

  origin0[0]=part->Vx(); //[cm]
  origin0[1]=part->Vy(); //[cm]
  origin0[2]=part->Vz(); //[cm]
  //
  // Put decay products on the stack
  //
  for (int i = 1; i < np; i++) {
         TParticle* iparticle = (TParticle *) particles->At(i);
         Int_t kf   = iparticle->GetPdgCode();
         Int_t ksc  = iparticle->GetStatusCode();
         Int_t jpa  = iparticle->GetFirstMother()-1; //jpa = 0 for daughters of beauty particles
         Int_t iparent = (jpa > 0) ? pParent[jpa] : iTrack;

         och[0] = origin0[0]+iparticle->Vx(); //[cm]
         och[1] = origin0[1]+iparticle->Vy(); //[cm]
         och[2] = origin0[2]+iparticle->Vz(); //[cm]
         pc[0]  = iparticle->Px(); //[GeV/c]
         pc[1]  = iparticle->Py(); //[GeV/c]
         pc[2]  = iparticle->Pz(); //[GeV/c]
         tof = part->T()+iparticle->T();

         AliDebug(1,Form("FirstMother = %d e indicePart = %d e pdg = %d \n",jpa,i,kf));

         PushTrack(trackIt[i], iparent, kf, pc, och, polar,tof, kPDecay, nt, 1., ksc);
         if(trackIt[i]==1) AliDebug(1,Form("Trackable particles: %d e pdg %d \n",i,kf));
         pParent[i] = nt;
         KeepTrack(nt);
         SetHighWaterMark(nt);
         }// Particle loop
         particles->Clear();
     	 if (trackIt)    delete[] trackIt;
         if (pParent)    delete[] pParent;
       }
  Info("Generate","AliGenEvtGen DONE");
  }

//////////////////////////////////////////////////////////////////////////////////////////
Int_t AliGenEvtGen::GetFlavour(Int_t pdgCode)
  {
  //
  // return the flavour of a particle
  // input: pdg code of the particle
  // output: Int_t
  //         3 in case of strange (open and hidden)
  //         4 in case of charm (")
  //         5 in case of beauty (")
  //
  Int_t pdg = TMath::Abs(pdgCode);
  //Resonance
  if (pdg > 100000) pdg %= 100000;
  if(pdg > 10000)  pdg %= 10000;
  // meson ?
  if(pdg > 10) pdg/=100;
  // baryon ?
  if(pdg > 10) pdg/=10;
  return pdg;
  }

/////////////////////////////////////////////////////////////////////////////////////////
Bool_t AliGenEvtGen::SetUserDecayTable(Char_t *path)
  {
  //
  //Set the path of user decay table if it is defined
  //
  //put a comment to control if path exists
  if(gSystem->AccessPathName(path))
    {
    AliWarning("Attention: This path not exist!\n");
    return kFALSE;
    }
  fUserDecayTablePath = path;
  fUserDecay = kTRUE;
  return kTRUE;
  }
<commit_msg>Bug fix: nt was uninitialized and no check was done on the result of PushTrack leading to seg fault in KeepTrack when particle was not pushed (e.g. PDG not known)<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.                  *
***************************************************************************/
///////////////////////////////////////////////////////////////////////////
//  Class to generate decays of particles generated by a                 //
//  previous generator. It works as a generator, but pratically it       //
//  performs only decays. It works with this scheme: first loops over    //
//  particles on the stack, selects those to be decayed, decays them     //
//  and then pushes the decay products on the stack.                     //
//                                                                       //
//  Giuseppe E. Bruno            &    Fiorella Fionda                    //
//  (Giuseppe.Bruno@ba.infn.it)       (Fiorella.Fionda@ba.infn.it)       //
///////////////////////////////////////////////////////////////////////////

#include "AliStack.h"
#include "AliGenEvtGen.h"
#include "AliRun.h"
#include "AliLog.h"
#include <TParticle.h>

ClassImp(AliGenEvtGen)
///////////////////////////////////////////////////////////////////////////
AliGenEvtGen::AliGenEvtGen():
  fStack(0x0),
  fDecayer(0x0),
  fForceDecay(kAll),
  fSwitchOff(kBeautyPart),
  fUserDecay(kFALSE),
  fUserDecayTablePath(0x0)
  {
  //
  // Default Construction
  //
  }
///////////////////////////////////////////////////////////////////////////////////////////
AliGenEvtGen::~AliGenEvtGen()
  {
  //
  // Standard Destructor
  //
  if(fStack) {delete fStack;}
  fStack = 0;
  if(fDecayer) {delete fDecayer;}
  fDecayer = 0;
  if(fUserDecayTablePath) {delete fUserDecayTablePath;}
  fUserDecayTablePath = 0;
  }
///////////////////////////////////////////////////////////////////////////////////////////

void AliGenEvtGen::Init()
  {
  //
  // Standard AliGenerator Initializer - no input
  // 1) initialize EvtGen with default decay and particle table
  // 2) set the decay mode to force particle
  // 3) set a user decay table if defined
  //
  if(fDecayer)
  {
  AliWarning("AliGenEvtGen already initialized!!!");
  return;
  }
  fDecayer = new AliDecayerEvtGen();
  fDecayer->Init(); //read the default decay table DECAY.DEC and particle table

  //if is set a decay mode: default decay mode is kAll
  fDecayer->SetForceDecay(fForceDecay);
  fDecayer->ForceDecay();

  //if is defined a user decay table
  if(fUserDecay)
    {
    fDecayer->SetDecayTablePath(fUserDecayTablePath);
    fDecayer->ReadDecayTable();
    }
  }

/////////////////////////////////////////////////////////////////////////////////////////////
void AliGenEvtGen::Generate()
  {
  //
  //Generate method - Input none - Output none
  //For each event:
  //1)return the stack of the previous generator and select particles to be decayed by EvtGen
  //2)decay particles selected and put the decay products on the stack
  //
  //
  Float_t polar[3]= {0,0,0};  // Polarisation of daughter particles
  Float_t origin0[3];         // Origin of the parent particle
  Float_t pc[3], och[3]; // Momentum and origin of the children particles from EvtGen
  Float_t tof;
  Int_t nPrimsPythia;
  TLorentzVector *mom=new TLorentzVector();
  static TClonesArray *particles;
  if(!particles) particles = new TClonesArray("TParticle",1000);
  fStack = AliRunLoader::Instance()->Stack();
  if(!fStack) {Info("Generate","Error: No stack found!"); return;}
  nPrimsPythia = fStack->GetNprimary();
  AliDebug(1,Form("nPrimsPythia = %d \n",nPrimsPythia));
  for (Int_t iTrack = 0; iTrack < nPrimsPythia; ++iTrack) {
  TParticle *part = fStack->Particle(iTrack);
  Int_t pdg=part->GetPdgCode();

  AliDebug(1,Form("GetFlavour = %d e pdg = %d \n",GetFlavour(pdg),pdg));

  switch(fSwitchOff)
  {
  case kAllPart:
  break;
  case kBeautyPart:
  if(GetFlavour(pdg)!=5) continue;
  break;
  case kCharmPart:
  if(GetFlavour(pdg)!=4) continue;
  break;
  }

  //check if particle is already decayed by Pythia
  if(part->GetStatusCode() != 1 || part->GetNDaughters()>0)
    {
    AliDebug(1,Form("Attention: particle %d is already decayed by Pythia!",pdg));
    continue;
    }

  part->SetStatusCode(11); //Set particle as decayed : change the status code
  part->SetBit(kDoneBit);
  part->ResetBit(kTransportBit);

  mom->SetPxPyPzE(part->Px(),part->Py(),part->Pz(),part->Energy());
  Int_t np;

   do{
     fDecayer->Decay(part->GetPdgCode(),mom);
     np = fDecayer->ImportParticles(particles);
     }while(np<0);

  Int_t* trackIt    = new Int_t[np];
  Int_t* pParent   = new Int_t[np];
  AliDebug(1,Form("np = %d \n",np));

  for (int i = 0; i < np; i++) {
             pParent[i]   = -1;
             trackIt[i]   =  0;
         }
  //select trackable particle
  if (np >1) {
    TParticle* iparticle =  0;//(TParticle *) particles->At(0);//parent particle
   for (int i = 1; i<np ; i++) {
     iparticle = (TParticle*) particles->At(i);
     Int_t ks = iparticle->GetStatusCode();

     //track last decay products
     if(ks==1) trackIt[i]=1;

     }//decay particles loop

  }// if decay products

  origin0[0]=part->Vx(); //[cm]
  origin0[1]=part->Vy(); //[cm]
  origin0[2]=part->Vz(); //[cm]
  //
  // Put decay products on the stack
  //
  for (int i = 1; i < np; i++) {
         TParticle* iparticle = (TParticle *) particles->At(i);
         Int_t kf   = iparticle->GetPdgCode();
         Int_t ksc  = iparticle->GetStatusCode();
         Int_t jpa  = iparticle->GetFirstMother()-1; //jpa = 0 for daughters of beauty particles
         Int_t iparent = (jpa > 0) ? pParent[jpa] : iTrack;

         och[0] = origin0[0]+iparticle->Vx(); //[cm]
         och[1] = origin0[1]+iparticle->Vy(); //[cm]
         och[2] = origin0[2]+iparticle->Vz(); //[cm]
         pc[0]  = iparticle->Px(); //[GeV/c]
         pc[1]  = iparticle->Py(); //[GeV/c]
         pc[2]  = iparticle->Pz(); //[GeV/c]
         tof = part->T()+iparticle->T();

         AliDebug(1,Form("FirstMother = %d e indicePart = %d e pdg = %d \n",jpa,i,kf));

         Int_t nt = -1;
         PushTrack(trackIt[i], iparent, kf, pc, och, polar,tof, kPDecay, nt, 1., ksc);
         if (nt < 0) {
           AliWarning(Form("Particle %i, pdg = %i, could not be pushed and will be skipped.", i, kf));
           continue;
         }
         if(trackIt[i]==1) AliDebug(1,Form("Trackable particles: %d e pdg %d \n",i,kf));
         pParent[i] = nt;
         KeepTrack(nt);
         SetHighWaterMark(nt);
         }// Particle loop
         particles->Clear();
     	 if (trackIt)    delete[] trackIt;
         if (pParent)    delete[] pParent;
       }
  Info("Generate","AliGenEvtGen DONE");
  }

//////////////////////////////////////////////////////////////////////////////////////////
Int_t AliGenEvtGen::GetFlavour(Int_t pdgCode)
  {
  //
  // return the flavour of a particle
  // input: pdg code of the particle
  // output: Int_t
  //         3 in case of strange (open and hidden)
  //         4 in case of charm (")
  //         5 in case of beauty (")
  //
  Int_t pdg = TMath::Abs(pdgCode);
  //Resonance
  if (pdg > 100000) pdg %= 100000;
  if(pdg > 10000)  pdg %= 10000;
  // meson ?
  if(pdg > 10) pdg/=100;
  // baryon ?
  if(pdg > 10) pdg/=10;
  return pdg;
  }

/////////////////////////////////////////////////////////////////////////////////////////
Bool_t AliGenEvtGen::SetUserDecayTable(Char_t *path)
  {
  //
  //Set the path of user decay table if it is defined
  //
  //put a comment to control if path exists
  if(gSystem->AccessPathName(path))
    {
    AliWarning("Attention: This path not exist!\n");
    return kFALSE;
    }
  fUserDecayTablePath = path;
  fUserDecay = kTRUE;
  return kTRUE;
  }
<|endoftext|>


<commit_before>#include "demo/conway/conway.h"

#include "etl/attribute_macros.h"

#include "vga/rast/bitmap_1.h"
#include "vga/arena.h"
#include "vga/graphics_1.h"
#include "vga/measurement.h"
#include "vga/timing.h"
#include "vga/vga.h"

#include "demo/input.h"

namespace demo {
namespace conway {

/*
 * Result of a bit-parallel addition operation: a pair of bit vectors
 * representing sum and carry.
 */
struct AddResult {
  unsigned sum;
  unsigned carry;
};

/*
 * Bit-parallel half adder: adds corresponding bits of two 32-bit vectors,
 * producing sum and carry vectors.
 */
static ETL_INLINE AddResult half_add(unsigned a, unsigned b) {
  return { a ^ b, a & b };
}

/*
 * Bit-parallel full adder: add corresponding bits of *three* 32-bit vectors,
 * producing sum and carry vectors.
 */
static ETL_INLINE AddResult full_add(unsigned a, unsigned b, unsigned c) {
  AddResult r0 = half_add(a, b);
  AddResult r1 = half_add(r0.sum, c);
  return { r1.sum, r0.carry | r1.carry };
}

/*
 * Step the automaton for the 32 cells contained in current[1], using the
 * neighboring bit vectors for context.
 */
__attribute__((section(".ramcode")))
static ETL_INLINE unsigned col_step(unsigned above[3],
                                unsigned current[3],
                                unsigned below[3]) {
  /*
   * Compute row-wise influence sums.  This produces 96 2-bit sums (represented
   * as three pairs of 32-vectors) giving the number of live cells in the 1D
   * Moore neighborhood around each position.
   */
  AddResult a_inf = full_add((above[1] << 1) | (above[0] >> 31),
                             above[1],
                             (above[1] >> 1) | (above[2] << 31));
  AddResult c_inf = half_add((current[1] << 1) | (current[0] >> 31),
                             /* middle bits of current[1] don't count */
                             (current[1] >> 1) | (current[2] << 31));
  AddResult b_inf = full_add((below[1] << 1) | (below[0] >> 31),
                             below[1],
                             (below[1] >> 1) | (below[2] << 31));

  /*
   * Sum the row-wise sums into a two-dimensional Moore neighborhood population
   * count.  Such a count can overflow into four bits, but we don't care: Conway
   * has the same result for 8/9 and 0/1 (the cell is cleared in both cases).
   *
   * Thus, we don't need a four-bit addition.  Instead, we just retain the
   * carry output from the two intermediate additions and use it as a mask.
   */
  AddResult next0 = full_add(a_inf.sum, c_inf.sum, b_inf.sum);
  AddResult next1a = full_add(a_inf.carry, next0.carry, b_inf.carry);
  AddResult next1b = half_add(c_inf.carry, next1a.sum);

  /*
   * Apply Niemiec's optimization: OR the current cell state vector into the
   * 9-cell neighborhoold population count to derive the new state cheaply.  The
   * cell is set iff its three-bit sum is 0b011.
   */
  return (next0.sum | current[1])
       & next1b.sum
       & ~next1a.carry
       & ~next1b.carry;
}

/*
 * Advance the automaton.
 *  - current_map is the framebuffer (or equivalent bitmap) holding the current
 *    state.
 *  - next_map is a framebuffer (bitmap) that will be filled in.
 *  - width is the width of both buffers in words.
 *  - height is the height of both buffers in lines.
 */
static void step(unsigned const *current_map,
          unsigned *next_map,
          unsigned width,
          unsigned height);

#define ADV(name, next) \
  name[0] = name[1]; \
  name[1] = name[2]; \
  name[2] = (next)

__attribute__((section(".ramcode")))
void step(unsigned const *current_map,
          unsigned *next_map,
          unsigned width,
          unsigned height) {
  // We keep sliding windows of state in these arrays.
  unsigned above[3] = { 0, 0, 0 };
  unsigned current[3] = { 0, 0, 0 };
  unsigned below[3] = { 0, 0, 0 };

  // Bootstrap for first column of first row.
  current[0] = current[1] = 0;
  current[2] = current_map[0];

  below[0] = below[1] = 0;
  below[2] = current_map[width];

  // First row, wherein above[x] = 0, less final column
  for (unsigned x = 0; x < width - 1; ++x) {
    ADV(current, current_map[x + 1]);
    ADV(below,   current_map[width + x + 1]);
    next_map[x] = col_step(above, current, below);
  }

  // Final column of first row, wherein we cannot fetch next values.
  ADV(current, 0);
  ADV(below, 0);
  next_map[width - 1] = col_step(above, current, below);

  // Remaining rows except the last.
  for (unsigned y = 1; y < height - 1; ++y) {
    unsigned offset = y * width;

    // Bootstrap row like we did for row 1.
    above[0] = above[1] = 0;
    current[0] = current[1] = 0;
    below[0] = below[1] = 0;

    above[2] = current_map[offset - width];
    current[2] = current_map[offset];
    below[2] = current_map[offset + width];

    for (unsigned x = 0; x < width - 1; ++x) {
      ADV(above, current_map[offset - width + x + 1]);
      ADV(current, current_map[offset + x + 1]);
      ADV(below, current_map[offset + width + x + 1]);
      next_map[offset + x] = col_step(above, current, below);
    }

    // Last column.
    ADV(above, 0);
    ADV(current, 0);
    ADV(below, 0);
    next_map[offset + width - 1] = col_step(above, current, below);
  }

  // Final row, wherein below[x] = 0.
  unsigned offset = width * (height - 1);
  above[0] = above[1] = 0;
  current[0] = current[1] = 0;
  below[0] = below[1] = below[2] = 0;

  above[2] = current_map[offset - width];
  current[2] = current_map[offset];

  for (unsigned x = 0; x < width - 1; ++x) {
    ADV(above, current_map[offset - width + x + 1]);
    ADV(current, current_map[offset + x + 1]);
    next_map[offset + x] = col_step(above, current, below);
  }

  // Final column
  ADV(above, 0);
  ADV(current, 0);
  next_map[offset + width - 1] = col_step(above, current, below);
}

static constexpr unsigned conway_cols = 800;
static constexpr unsigned conway_rows = 600;

static vga::rast::Bitmap_1 rasterizer(conway_cols, conway_rows);

// Cells will be set at boot when rand() is less than this.
static unsigned constexpr boot_threshold = 0x20000000;

// Seed and state variable for random number generation.
static unsigned seed = 1118;

// A simple linear congruential random number generator.
// (Coefficients borrowed from GCC.)
static unsigned rand() {
  seed = ((seed * 1103515245) + 12345) & 0x7FFFFFFF;
  return seed;
}

static void set_random_cells(unsigned threshold) {
  vga::Graphics1 g = rasterizer.make_bg_graphics();
  for (unsigned y = 0; y < conway_rows; ++y) {
    for (unsigned x = 0; x < conway_cols; ++x) {
      if (rand() < threshold) g.set_pixel(x, y);
    }
  }
}

static vga::Band const band = { &rasterizer, 600, nullptr };

void run(bool clear_first) {
  vga::sync_to_vblank();
  rasterizer.activate(vga::timing_vesa_800x600_60hz);
  rasterizer.set_fg_color(0b111111);
  rasterizer.set_bg_color(0b010000);

  vga::configure_band_list(&band);

  if (clear_first) {
    vga::Graphics1 g = rasterizer.make_bg_graphics();
    g.clear_all();
    set_random_cells(boot_threshold);
    rasterizer.flip();
  }

  input_init();
  vga::msigs_init();
  vga::video_on();

  while (!user_button_pressed()) {
    vga::msig_a_set();

    step(static_cast<unsigned const *>(rasterizer.get_fg_buffer()),
         static_cast<unsigned *>(rasterizer.get_bg_buffer()),
         conway_cols / 32,
         conway_rows);

    vga::msig_a_clear();

    if (rasterizer.can_bg_use_bitband()) {
      if (center_button_pressed()) set_random_cells(0x10000000);
    }

    vga::wait_for_vblank();
    rasterizer.flip_now();
  }

  vga::video_off();

  vga::configure_band_list(nullptr);
  vga::arena_reset();
}

}  // namespace conway
}  // namespace demo

<commit_msg>demo/conway: sync to vblank at teardown.<commit_after>#include "demo/conway/conway.h"

#include "etl/attribute_macros.h"

#include "vga/rast/bitmap_1.h"
#include "vga/arena.h"
#include "vga/graphics_1.h"
#include "vga/measurement.h"
#include "vga/timing.h"
#include "vga/vga.h"

#include "demo/input.h"

namespace demo {
namespace conway {

/*
 * Result of a bit-parallel addition operation: a pair of bit vectors
 * representing sum and carry.
 */
struct AddResult {
  unsigned sum;
  unsigned carry;
};

/*
 * Bit-parallel half adder: adds corresponding bits of two 32-bit vectors,
 * producing sum and carry vectors.
 */
static ETL_INLINE AddResult half_add(unsigned a, unsigned b) {
  return { a ^ b, a & b };
}

/*
 * Bit-parallel full adder: add corresponding bits of *three* 32-bit vectors,
 * producing sum and carry vectors.
 */
static ETL_INLINE AddResult full_add(unsigned a, unsigned b, unsigned c) {
  AddResult r0 = half_add(a, b);
  AddResult r1 = half_add(r0.sum, c);
  return { r1.sum, r0.carry | r1.carry };
}

/*
 * Step the automaton for the 32 cells contained in current[1], using the
 * neighboring bit vectors for context.
 */
__attribute__((section(".ramcode")))
static ETL_INLINE unsigned col_step(unsigned above[3],
                                unsigned current[3],
                                unsigned below[3]) {
  /*
   * Compute row-wise influence sums.  This produces 96 2-bit sums (represented
   * as three pairs of 32-vectors) giving the number of live cells in the 1D
   * Moore neighborhood around each position.
   */
  AddResult a_inf = full_add((above[1] << 1) | (above[0] >> 31),
                             above[1],
                             (above[1] >> 1) | (above[2] << 31));
  AddResult c_inf = half_add((current[1] << 1) | (current[0] >> 31),
                             /* middle bits of current[1] don't count */
                             (current[1] >> 1) | (current[2] << 31));
  AddResult b_inf = full_add((below[1] << 1) | (below[0] >> 31),
                             below[1],
                             (below[1] >> 1) | (below[2] << 31));

  /*
   * Sum the row-wise sums into a two-dimensional Moore neighborhood population
   * count.  Such a count can overflow into four bits, but we don't care: Conway
   * has the same result for 8/9 and 0/1 (the cell is cleared in both cases).
   *
   * Thus, we don't need a four-bit addition.  Instead, we just retain the
   * carry output from the two intermediate additions and use it as a mask.
   */
  AddResult next0 = full_add(a_inf.sum, c_inf.sum, b_inf.sum);
  AddResult next1a = full_add(a_inf.carry, next0.carry, b_inf.carry);
  AddResult next1b = half_add(c_inf.carry, next1a.sum);

  /*
   * Apply Niemiec's optimization: OR the current cell state vector into the
   * 9-cell neighborhoold population count to derive the new state cheaply.  The
   * cell is set iff its three-bit sum is 0b011.
   */
  return (next0.sum | current[1])
       & next1b.sum
       & ~next1a.carry
       & ~next1b.carry;
}

/*
 * Advance the automaton.
 *  - current_map is the framebuffer (or equivalent bitmap) holding the current
 *    state.
 *  - next_map is a framebuffer (bitmap) that will be filled in.
 *  - width is the width of both buffers in words.
 *  - height is the height of both buffers in lines.
 */
static void step(unsigned const *current_map,
          unsigned *next_map,
          unsigned width,
          unsigned height);

#define ADV(name, next) \
  name[0] = name[1]; \
  name[1] = name[2]; \
  name[2] = (next)

__attribute__((section(".ramcode")))
void step(unsigned const *current_map,
          unsigned *next_map,
          unsigned width,
          unsigned height) {
  // We keep sliding windows of state in these arrays.
  unsigned above[3] = { 0, 0, 0 };
  unsigned current[3] = { 0, 0, 0 };
  unsigned below[3] = { 0, 0, 0 };

  // Bootstrap for first column of first row.
  current[0] = current[1] = 0;
  current[2] = current_map[0];

  below[0] = below[1] = 0;
  below[2] = current_map[width];

  // First row, wherein above[x] = 0, less final column
  for (unsigned x = 0; x < width - 1; ++x) {
    ADV(current, current_map[x + 1]);
    ADV(below,   current_map[width + x + 1]);
    next_map[x] = col_step(above, current, below);
  }

  // Final column of first row, wherein we cannot fetch next values.
  ADV(current, 0);
  ADV(below, 0);
  next_map[width - 1] = col_step(above, current, below);

  // Remaining rows except the last.
  for (unsigned y = 1; y < height - 1; ++y) {
    unsigned offset = y * width;

    // Bootstrap row like we did for row 1.
    above[0] = above[1] = 0;
    current[0] = current[1] = 0;
    below[0] = below[1] = 0;

    above[2] = current_map[offset - width];
    current[2] = current_map[offset];
    below[2] = current_map[offset + width];

    for (unsigned x = 0; x < width - 1; ++x) {
      ADV(above, current_map[offset - width + x + 1]);
      ADV(current, current_map[offset + x + 1]);
      ADV(below, current_map[offset + width + x + 1]);
      next_map[offset + x] = col_step(above, current, below);
    }

    // Last column.
    ADV(above, 0);
    ADV(current, 0);
    ADV(below, 0);
    next_map[offset + width - 1] = col_step(above, current, below);
  }

  // Final row, wherein below[x] = 0.
  unsigned offset = width * (height - 1);
  above[0] = above[1] = 0;
  current[0] = current[1] = 0;
  below[0] = below[1] = below[2] = 0;

  above[2] = current_map[offset - width];
  current[2] = current_map[offset];

  for (unsigned x = 0; x < width - 1; ++x) {
    ADV(above, current_map[offset - width + x + 1]);
    ADV(current, current_map[offset + x + 1]);
    next_map[offset + x] = col_step(above, current, below);
  }

  // Final column
  ADV(above, 0);
  ADV(current, 0);
  next_map[offset + width - 1] = col_step(above, current, below);
}

static constexpr unsigned conway_cols = 800;
static constexpr unsigned conway_rows = 600;

static vga::rast::Bitmap_1 rasterizer(conway_cols, conway_rows);

// Cells will be set at boot when rand() is less than this.
static unsigned constexpr boot_threshold = 0x20000000;

// Seed and state variable for random number generation.
static unsigned seed = 1118;

// A simple linear congruential random number generator.
// (Coefficients borrowed from GCC.)
static unsigned rand() {
  seed = ((seed * 1103515245) + 12345) & 0x7FFFFFFF;
  return seed;
}

static void set_random_cells(unsigned threshold) {
  vga::Graphics1 g = rasterizer.make_bg_graphics();
  for (unsigned y = 0; y < conway_rows; ++y) {
    for (unsigned x = 0; x < conway_cols; ++x) {
      if (rand() < threshold) g.set_pixel(x, y);
    }
  }
}

static vga::Band const band = { &rasterizer, 600, nullptr };

void run(bool clear_first) {
  vga::sync_to_vblank();
  rasterizer.activate(vga::timing_vesa_800x600_60hz);
  rasterizer.set_fg_color(0b111111);
  rasterizer.set_bg_color(0b010000);

  vga::configure_band_list(&band);

  if (clear_first) {
    vga::Graphics1 g = rasterizer.make_bg_graphics();
    g.clear_all();
    set_random_cells(boot_threshold);
    rasterizer.flip();
  }

  input_init();
  vga::msigs_init();
  vga::video_on();

  while (!user_button_pressed()) {
    vga::msig_a_set();

    step(static_cast<unsigned const *>(rasterizer.get_fg_buffer()),
         static_cast<unsigned *>(rasterizer.get_bg_buffer()),
         conway_cols / 32,
         conway_rows);

    vga::msig_a_clear();

    if (rasterizer.can_bg_use_bitband()) {
      if (center_button_pressed()) set_random_cells(0x10000000);
    }

    vga::wait_for_vblank();
    rasterizer.flip_now();
  }

  vga::sync_to_vblank();
  vga::video_off();

  vga::configure_band_list(nullptr);
  vga::arena_reset();
}

}  // namespace conway
}  // namespace demo

<|endoftext|>


<commit_before>/*Copyright 2014 George Karagoulis

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 "cryptopp_cryptor.h"
#include "cryptopp_sinks.h"
#include "gutil_d.h"
#include "gutil_exception.h"
#include "gutil_file.h"
#include "gutil_smartpointer.h"
#include "gutil_cryptopp_hash.h"
#include <cryptopp/gcm.h>
#include <cryptopp/aes.h>
#include <cryptopp/osrng.h>
#include <cryptopp/sha3.h>
USING_NAMESPACE_GUTIL;

// These are some constants for the type of encryption we've chosen
#define KEYLENGTH   32

// The length of the second key, if we're using it
#define KEYLENGTH2  64

#define DEFAULT_CHUNK_SIZE 1024

namespace
{

// These are allocated at compile time, so consumers
//   of our class don't need to include cryptopp headers
struct d_t
{
    ::CryptoPP::AutoSeededX917RNG< ::CryptoPP::AES> rng;
    ::CryptoPP::GCM< ::CryptoPP::AES>::Encryption enc;
    ::CryptoPP::GCM< ::CryptoPP::AES>::Decryption dec;
    byte key[KEYLENGTH];
    byte key2[KEYLENGTH2];
};

}

NAMESPACE_GUTIL1(CryptoPP);

static void __compute_password_hash(byte result[KEYLENGTH], const char *password)
{
    ::CryptoPP::SHA3_256().CalculateDigest(result, (byte const *)password, password ? strlen(password) : 0);
}

static void __compute_keyfile_hash(byte result[KEYLENGTH], const char *keyfile, IProgressHandler *ph = 0)
{
    SmartPointer<IInput> in;
    if(keyfile != NULL && strlen(keyfile) > 0){
        File *f = new File(keyfile);
        f->Open(File::OpenRead);
        in = f;
    }
    ::GUtil::CryptoPP::Hash<SHA3_256>().ComputeHash(result, in, DEFAULT_CHUNK_SIZE, ph);
}

static void __compute_password_hash2(byte result[KEYLENGTH2], const char *password)
{
    ::CryptoPP::SHA3_512().CalculateDigest(result, (byte const *)password, password ? strlen(password) : 0);
}

Cryptor::Cryptor(const char *password, const char *keyfile)
{
    G_D_INIT();
    ChangePassword(password, keyfile);
}

Cryptor::Cryptor(const Cryptor &other)
{
    G_D_INIT();
    G_D;
    memcpy(d->key, ((d_t *)other.d)->key, KEYLENGTH);
    memcpy(d->key2, ((d_t *)other.d)->key2, KEYLENGTH2);
}

Cryptor::~Cryptor()
{
    G_D_UNINIT();
}

bool Cryptor::CheckPassword(const char *password, const char *keyfile) const
{
    G_D;
    byte buf_key[KEYLENGTH] = {};
    byte buf_key2[KEYLENGTH2] = {};
    if(keyfile == NULL || strlen(keyfile) == 0){
        // Only the password was given (or even a null password)
        __compute_password_hash(buf_key, password);
    }
    else{
        // A password and keyfile were given
        __compute_keyfile_hash(buf_key, keyfile);
    }
    __compute_password_hash2(buf_key2, password);
    return (0 == memcmp(d->key, buf_key, sizeof(buf_key))) &&
           (0 == memcmp(d->key2, buf_key2, sizeof(buf_key2)));
}

void Cryptor::ChangePassword(const char *password, const char *keyfile)
{
    G_D;
    if(keyfile == NULL || strlen(keyfile) == 0){
        // Only the password was given (or even a null password)
        __compute_password_hash(d->key, password);
    }
    else{
        // A password and keyfile were given
        __compute_keyfile_hash(d->key, keyfile);
    }
    __compute_password_hash2(d->key2, password);
}

void Cryptor::EncryptData(IOutput *out,
                          IInput *pData,
                          IInput *aData,
                          GUINT32 chunk_size,
                          IProgressHandler *ph) const
{
    G_D;
    byte iv[IVLength];
    if(ph) ph->ProgressUpdated(0);

    // Initialize a random IV and initialize the encryptor
    d->rng.GenerateBlock(iv, sizeof(iv));
    d->enc.SetKeyWithIV(d->key, KEYLENGTH, iv, IVLength);

    // First write the IV
    out->WriteBytes(iv, sizeof(iv));

    GUINT32 len = pData ? pData->BytesAvailable() : 0;
    if(len == GUINT32_MAX)
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Source invalid: Length must be known");

    GUINT32 read = 0;
    GUINT32 to_read = chunk_size == 0 ? len : chunk_size;
    GUINT32 buf_sz = to_read;
    ::CryptoPP::AuthenticatedEncryptionFilter ef(
                d->enc,
                new OutputInterfaceSink(*out),
                false,
                TagLength);

    // First pass the authenticated data. Our second key goes in here.
    ef.ChannelPut(::CryptoPP::AAD_CHANNEL, d->key2, KEYLENGTH2);

    // If they gave us additional auth data, add it here
    if(aData && 0 < aData->BytesAvailable())
    {
        const GUINT32 len = aData->BytesAvailable();
        SmartArrayPointer<byte> a(new byte[len]);
        if(len != aData->ReadBytes(a, len, len))
            THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from auth data source");
        ef.ChannelPut(::CryptoPP::AAD_CHANNEL, a.Data(), len);
    }
    ef.ChannelMessageEnd(::CryptoPP::AAD_CHANNEL);

    // Then read and pass the plaintext data
    if(read < len)
    {
        SmartArrayPointer<byte> buf(new byte[buf_sz]);
        while(read < len)
        {
            GASSERT(pData);

            if((read + to_read) > len)
                to_read = len - read;

            if(to_read != pData->ReadBytes(buf, buf_sz, to_read))
                THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

            ef.Put(buf, to_read, true);
            read += to_read;

            if(ph){
                ph->ProgressUpdated(((float)read / len) * 100);
                if(ph->CancelOperation())
                    THROW_NEW_GUTIL_EXCEPTION(CancelledOperationException);
            }
        }
    }
    ef.MessageEnd();
    out->Flush();
    if(ph) ph->ProgressUpdated(100);
}

void Cryptor::DecryptData(IOutput *out,
                          IRandomAccessInput *cData,
                          IInput *aData,
                          GUINT32 chunk_size,
                          IProgressHandler *ph) const
{
    G_D;
    GUINT32 len;
    if((len = cData->BytesAvailable()) < (IVLength + TagLength))
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Invalid data length");
    len = len - (IVLength + TagLength);

    // Read the IV from the start of the source
    byte iv[IVLength];
    if(IVLength != cData->ReadBytes(iv, sizeof(iv), IVLength))
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

    // Read the MAC tag at the end of the crypttext
    byte mac[TagLength];
    const GUINT32 cData_startPos = cData->Pos();
    cData->Seek(cData->Length() - TagLength);
    if(TagLength != cData->ReadBytes(mac, TagLength, TagLength))
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

    // Seek back to the start of the message
    cData->Seek(cData_startPos);

    // Initialize the decryptor
    d->dec.SetKeyWithIV(d->key, KEYLENGTH, iv, IVLength);
    try
    {
        GUINT32 read = 0;
        GUINT32 to_read = chunk_size == 0 ? len : chunk_size;
        GUINT32 buf_sz = to_read;
        ::CryptoPP::AuthenticatedDecryptionFilter df(
                    d->dec,
                    out == NULL ? NULL : new OutputInterfaceSink(*out),
                    ::CryptoPP::AuthenticatedDecryptionFilter::THROW_EXCEPTION |
                    ::CryptoPP::AuthenticatedDecryptionFilter::MAC_AT_BEGIN,
                    TagLength);

        // We have to give it the mac before everything else in order to decrypt both
        //  the pData and the aData
        df.Put(mac, TagLength);

        // Pass the authenticated data before the plaintext:
        df.ChannelPut(::CryptoPP::AAD_CHANNEL, d->key2, KEYLENGTH2);

        // If they gave us additional auth data, add it here
        if(aData && 0 < aData->BytesAvailable())
        {
            const GUINT32 len = aData->BytesAvailable();
            SmartArrayPointer<byte> a(new byte[len]);
            if(len != aData->ReadBytes(a, len, len))
                THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from auth data source");
            df.ChannelPut(::CryptoPP::AAD_CHANNEL, a.Data(), len);
        }
        df.ChannelMessageEnd(::CryptoPP::AAD_CHANNEL);

        // Then read and pass the crypttext
        if(read < len)
        {
            SmartArrayPointer<byte> buf(new byte[buf_sz]);
            while(read < len)
            {
                if((read + to_read) > len)
                    to_read = len - read;

                if(to_read != cData->ReadBytes(buf, buf_sz, to_read))
                    THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

                df.Put(buf, to_read, true);
                read += to_read;

                if(ph){
                    ph->ProgressUpdated(((float)read / len) * 100);
                    if(ph->CancelOperation())
                        THROW_NEW_GUTIL_EXCEPTION(CancelledOperationException);
                }
            }
        }

        // This will throw an exception if authenticity validation failed
        df.MessageEnd();
    }
    catch(const ::CryptoPP::Exception &ex)
    {
        THROW_NEW_GUTIL_EXCEPTION2(AuthenticationException, ex.what());
    }
    if(out) out->Flush();
    if(ph) ph->ProgressUpdated(100);
}

END_NAMESPACE_GUTIL1;
<commit_msg>Now the IV is written at the end of the encrypted message, to simplify things on the receiving end so the message is not sandwiched in between two critical pieces of data. Now all the encryption metadata is at the end.<commit_after>/*Copyright 2014 George Karagoulis

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 "cryptopp_cryptor.h"
#include "cryptopp_sinks.h"
#include "gutil_d.h"
#include "gutil_exception.h"
#include "gutil_file.h"
#include "gutil_smartpointer.h"
#include "gutil_cryptopp_hash.h"
#include <cryptopp/gcm.h>
#include <cryptopp/aes.h>
#include <cryptopp/osrng.h>
#include <cryptopp/sha3.h>
USING_NAMESPACE_GUTIL;

// These are some constants for the type of encryption we've chosen
#define KEYLENGTH   32

// The length of the second key, if we're using it
#define KEYLENGTH2  64

#define DEFAULT_CHUNK_SIZE 1024

namespace
{

// These are allocated at compile time, so consumers
//   of our class don't need to include cryptopp headers
struct d_t
{
    ::CryptoPP::AutoSeededX917RNG< ::CryptoPP::AES> rng;
    ::CryptoPP::GCM< ::CryptoPP::AES>::Encryption enc;
    ::CryptoPP::GCM< ::CryptoPP::AES>::Decryption dec;
    byte key[KEYLENGTH];
    byte key2[KEYLENGTH2];
};

}

NAMESPACE_GUTIL1(CryptoPP);

static void __compute_password_hash(byte result[KEYLENGTH], const char *password)
{
    ::CryptoPP::SHA3_256().CalculateDigest(result, (byte const *)password, password ? strlen(password) : 0);
}

static void __compute_keyfile_hash(byte result[KEYLENGTH], const char *keyfile, IProgressHandler *ph = 0)
{
    SmartPointer<IInput> in;
    if(keyfile != NULL && strlen(keyfile) > 0){
        File *f = new File(keyfile);
        f->Open(File::OpenRead);
        in = f;
    }
    ::GUtil::CryptoPP::Hash<SHA3_256>().ComputeHash(result, in, DEFAULT_CHUNK_SIZE, ph);
}

static void __compute_password_hash2(byte result[KEYLENGTH2], const char *password)
{
    ::CryptoPP::SHA3_512().CalculateDigest(result, (byte const *)password, password ? strlen(password) : 0);
}

Cryptor::Cryptor(const char *password, const char *keyfile)
{
    G_D_INIT();
    ChangePassword(password, keyfile);
}

Cryptor::Cryptor(const Cryptor &other)
{
    G_D_INIT();
    G_D;
    memcpy(d->key, ((d_t *)other.d)->key, KEYLENGTH);
    memcpy(d->key2, ((d_t *)other.d)->key2, KEYLENGTH2);
}

Cryptor::~Cryptor()
{
    G_D_UNINIT();
}

bool Cryptor::CheckPassword(const char *password, const char *keyfile) const
{
    G_D;
    byte buf_key[KEYLENGTH] = {};
    byte buf_key2[KEYLENGTH2] = {};
    if(keyfile == NULL || strlen(keyfile) == 0){
        // Only the password was given (or even a null password)
        __compute_password_hash(buf_key, password);
    }
    else{
        // A password and keyfile were given
        __compute_keyfile_hash(buf_key, keyfile);
    }
    __compute_password_hash2(buf_key2, password);
    return (0 == memcmp(d->key, buf_key, sizeof(buf_key))) &&
           (0 == memcmp(d->key2, buf_key2, sizeof(buf_key2)));
}

void Cryptor::ChangePassword(const char *password, const char *keyfile)
{
    G_D;
    if(keyfile == NULL || strlen(keyfile) == 0){
        // Only the password was given (or even a null password)
        __compute_password_hash(d->key, password);
    }
    else{
        // A password and keyfile were given
        __compute_keyfile_hash(d->key, keyfile);
    }
    __compute_password_hash2(d->key2, password);
}

void Cryptor::EncryptData(IOutput *out,
                          IInput *pData,
                          IInput *aData,
                          GUINT32 chunk_size,
                          IProgressHandler *ph) const
{
    G_D;
    byte iv[IVLength];
    if(ph) ph->ProgressUpdated(0);

    // Initialize a random IV and initialize the encryptor
    d->rng.GenerateBlock(iv, sizeof(iv));
    d->enc.SetKeyWithIV(d->key, KEYLENGTH, iv, IVLength);

    GUINT32 len = pData ? pData->BytesAvailable() : 0;
    if(len == GUINT32_MAX)
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Source invalid: Length must be known");

    GUINT32 read = 0;
    GUINT32 to_read = chunk_size == 0 ? len : chunk_size;
    GUINT32 buf_sz = to_read;
    ::CryptoPP::AuthenticatedEncryptionFilter ef(
                d->enc,
                new OutputInterfaceSink(*out),
                false,
                TagLength);

    // First pass the authenticated data. Our second key goes in here.
    ef.ChannelPut(::CryptoPP::AAD_CHANNEL, d->key2, KEYLENGTH2);

    // If they gave us additional auth data, add it here
    if(aData && 0 < aData->BytesAvailable())
    {
        const GUINT32 len = aData->BytesAvailable();
        SmartArrayPointer<byte> a(new byte[len]);
        if(len != aData->ReadBytes(a, len, len))
            THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from auth data source");
        ef.ChannelPut(::CryptoPP::AAD_CHANNEL, a.Data(), len);
    }
    ef.ChannelMessageEnd(::CryptoPP::AAD_CHANNEL);

    // Then read and pass the plaintext data
    if(read < len)
    {
        SmartArrayPointer<byte> buf(new byte[buf_sz]);
        while(read < len)
        {
            GASSERT(pData);

            if((read + to_read) > len)
                to_read = len - read;

            if(to_read != pData->ReadBytes(buf, buf_sz, to_read))
                THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

            ef.Put(buf, to_read, true);
            read += to_read;

            if(ph){
                ph->ProgressUpdated(((float)read / len) * 100);
                if(ph->CancelOperation())
                    THROW_NEW_GUTIL_EXCEPTION(CancelledOperationException);
            }
        }
    }
    ef.MessageEnd();

    // Write the IV at the very end
    out->WriteBytes(iv, sizeof(iv));
    out->Flush();
    if(ph) ph->ProgressUpdated(100);
}

void Cryptor::DecryptData(IOutput *out,
                          IRandomAccessInput *cData,
                          IInput *aData,
                          GUINT32 chunk_size,
                          IProgressHandler *ph) const
{
    G_D;
    GUINT32 len;
    if((len = cData->BytesAvailable()) < (IVLength + TagLength))
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Invalid data length");
    len = len - (IVLength + TagLength);

    // Read the MAC tag and IV at the end of the crypttext
    byte mac_iv[TagLength + IVLength];
    cData->Seek(cData->Length() - sizeof(mac_iv));
    if(sizeof(mac_iv) != cData->ReadBytes(mac_iv, sizeof(mac_iv), sizeof(mac_iv)))
        THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

    // Seek back to the start of the message
    cData->Seek(0);

    // Initialize the decryptor
    d->dec.SetKeyWithIV(d->key, KEYLENGTH, mac_iv + TagLength, IVLength);
    try
    {
        GUINT32 read = 0;
        GUINT32 to_read = chunk_size == 0 ? len : chunk_size;
        GUINT32 buf_sz = to_read;
        ::CryptoPP::AuthenticatedDecryptionFilter df(
                    d->dec,
                    out == NULL ? NULL : new OutputInterfaceSink(*out),
                    ::CryptoPP::AuthenticatedDecryptionFilter::THROW_EXCEPTION |
                    ::CryptoPP::AuthenticatedDecryptionFilter::MAC_AT_BEGIN,
                    TagLength);

        // We have to give it the mac before everything else in order to decrypt both
        //  the pData and the aData
        df.Put(mac_iv, TagLength);

        // Pass the authenticated data before the plaintext:
        df.ChannelPut(::CryptoPP::AAD_CHANNEL, d->key2, KEYLENGTH2);

        // If they gave us additional auth data, add it here
        if(aData && 0 < aData->BytesAvailable())
        {
            const GUINT32 len = aData->BytesAvailable();
            SmartArrayPointer<byte> a(new byte[len]);
            if(len != aData->ReadBytes(a, len, len))
                THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from auth data source");
            df.ChannelPut(::CryptoPP::AAD_CHANNEL, a.Data(), len);
        }
        df.ChannelMessageEnd(::CryptoPP::AAD_CHANNEL);

        // Then read and pass the crypttext
        if(read < len)
        {
            SmartArrayPointer<byte> buf(new byte[buf_sz]);
            while(read < len)
            {
                if((read + to_read) > len)
                    to_read = len - read;

                if(to_read != cData->ReadBytes(buf, buf_sz, to_read))
                    THROW_NEW_GUTIL_EXCEPTION2(Exception, "Error reading from source");

                df.Put(buf, to_read, true);
                read += to_read;

                if(ph){
                    ph->ProgressUpdated(((float)read / len) * 100);
                    if(ph->CancelOperation())
                        THROW_NEW_GUTIL_EXCEPTION(CancelledOperationException);
                }
            }
        }

        // This will throw an exception if authenticity validation failed
        df.MessageEnd();
    }
    catch(const ::CryptoPP::Exception &ex)
    {
        THROW_NEW_GUTIL_EXCEPTION2(AuthenticationException, ex.what());
    }
    if(out) out->Flush();
    if(ph) ph->ProgressUpdated(100);
}

END_NAMESPACE_GUTIL1;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014 Nicholas Corgan (n.corgan@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#ifndef INCLUDED_PKMN_TYPES_PRNG_HPP
#define INCLUDED_PKMN_TYPES_PRNG_HPP

#include <cstdint>

#include <pkmn/config.hpp>
#include <pkmn/types/shared_ptr.hpp>

namespace pkmn
{
    class PKMN_API prng
    {
        public:

            typedef pkmn::shared_ptr<prng> sptr;
            static sptr get(unsigned int gen);

            virtual uint64_t lcrng() = 0;
            virtual uint32_t arng() = 0;
            virtual uint32_t mtrng() = 0;

            virtual ~prng() {}; //Can this be avoided?

        protected:

            prng() {};
    };
}

#endif /* INCLUDED_PKMN_TYPES_PRNG_HPP */
<commit_msg>Added Doxygen comments for PRNG class<commit_after>/*
 * Copyright (c) 2013-2014 Nicholas Corgan (n.corgan@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#ifndef INCLUDED_PKMN_TYPES_PRNG_HPP
#define INCLUDED_PKMN_TYPES_PRNG_HPP

#include <cstdint>

#include <pkmn/config.hpp>
#include <pkmn/types/shared_ptr.hpp>

namespace pkmn
{
    /*!
     * This class represents an in-game pseudorandom number generator (PRNG). The algorithms used by this class, while
     * weak, match those used in the generation specified in the factory function's "gen" parameter.
     *
     * This class operates as a pseudo-singleton. Instead of a single instance existing, a single instance exists for
     * each of the six generations, and each one is accessed by passing the appropriate parameter into the factory
     * function, as shown below:
     *

     * pkmn::prng::sptr gen3_instance = pkmn::prng::get(3);
     * pkmn::prng::sptr gen4_instance1 = pkmn::prng::get(4);
     * pkmn::prng::sptr gen4_instance2 = pkmn::prng::get(4);
     *

     *
     * All algorithms taken from: Bulbapedia
     */
    class PKMN_API prng
    {
        public:

            typedef pkmn::shared_ptr<prng> sptr;

            /*!
             * This is the PRNG's factory function.
             *
             * \param gen generation of desired PRNG
             * \return shared pointer to instance of specified generation's PRNG
             */
            static sptr get(unsigned int gen);

            /*!
             * Linear Congruential Random Number Generator (LCRNG)
             *
             * "In Generation III and Generation IV, the games use a 32 bit LCRNG.
             *
             *  ...
             *
             * This algorithm is used for the following:
             *  * Encrypting Pokémon data in the save file.
             *  * Generate the personality value of a wild encountered Pokémon.
             *  * Generate the individual values of a wild encountered Pokémon in Generation III and Generation IV.
             *  * Determining the species of a wild Pokémon.
             *  * Determining the Pokémon Lottery Corner lucky number.
             *  *Determining if an egg will be available at the Pokémon Day Care.
             *
             * In Generation V and Generation VI, the games instead use a 64 bit LCRNG..."
             *
             * Excerpt from: Bulbapedia
             *
             * \return next LCRNG value
             */
            virtual uint64_t lcrng() = 0;

            /*!
             * Alternative Pseudorandom Number Generator (ARNG)
             *
             * "The Generation IV games also use a different algorithm to alternate, reroll, or modify a previously randomly generated value...
             *
             * This algorithm is used for the following:
             *  * Shiny Pokémon Ranger Manaphy egg restriction.
             *  * Determining the species of a Pokémon swarm.
             *  * Determining the Pokémon in the Great Marsh.
             *  * Determining the Pokémon in the Trophy Garden.
             *  * Mystery Gift shininess restriction for Type 1 Wonder Card Pokémon (currently all released with variable Natures)."
             *
             * Excerpt from: Bulbapedia
             *
             * \return next ARNG value
             */
            virtual uint32_t arng() = 0;

            /*!
             * Mersenne Twister (MTRNG)
             *
             * "Found in Generation IV and later, the Mersenne Twister is another type of random number generator that produces 624 random numbers at once.
             * These random numbers are then stored and used when needed. When all 624 numbers are used, another set is generated.
             *
             * This algorithm is used for the following:
             *  * Egg PIDs in Generation IV.
             *  * Friendship Change Calculations.
             *  * Sprite Animations in Generation V.
             *  * Individual Values in Generation V.
             *  * AI Move decisions in Generation V."
             *
             * Excerpt from: Bulbapedia
             *
             * \return next MTRNG value
             */
            virtual uint32_t mtrng() = 0;

            virtual ~prng() {}; //Can this be avoided?

        protected:

            prng() {};
    };
}

#endif /* INCLUDED_PKMN_TYPES_PRNG_HPP */
<|endoftext|>


<commit_before>// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_MATCH_HPP
#define TAO_PEGTL_MATCH_HPP

#include <type_traits>

#include "apply_mode.hpp"
#include "config.hpp"
#include "nothing.hpp"
#include "require_apply.hpp"
#include "require_apply0.hpp"
#include "rewind_mode.hpp"

#include "internal/has_apply.hpp"
#include "internal/has_apply0.hpp"
#include "internal/has_unwind.hpp"
#include "internal/marker.hpp"
#include "internal/missing_apply.hpp"
#include "internal/missing_apply0.hpp"

#if defined( _MSC_VER )
#pragma warning( push )
#pragma warning( disable : 4702 )
#endif

namespace TAO_PEGTL_NAMESPACE
{
   namespace internal
   {
      template< typename Rule,
                apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename ParseInput,
                typename... States >
      [[nodiscard]] static auto match_no_control( ParseInput& in, States&&... st )
         -> decltype( Rule::template match< A, M, Action, Control >( in, st... ) )
      {
         return Rule::template match< A, M, Action, Control >( in, st... );
      }

      template< typename Rule,
                apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename ParseInput,
                typename... States >
      [[nodiscard]] static auto match_no_control( ParseInput& in, States&&... /*unused*/ )
         -> decltype( Rule::match( in ) )
      {
         return Rule::match( in );
      }

      template< typename Rule,
                apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename ParseInput,
                typename... States >
      [[nodiscard]] auto match_control_unwind( ParseInput& in, States&&... st )
      {
         if constexpr( has_unwind< Control< Rule >, void, const ParseInput&, States... > ) {
            try {
               return match_no_control< Rule, A, M, Action, Control >( in, st... );
            }
            catch( ... ) {
               Control< Rule >::unwind( static_cast< const ParseInput& >( in ), st... );
               throw;
            }
         }
         else {
            return match_no_control< Rule, A, M, Action, Control >( in, st... );
         }
      }

   }  // namespace internal

   template< typename Rule,
             apply_mode A,
             rewind_mode M,
             template< typename... >
             class Action,
             template< typename... >
             class Control,
             typename ParseInput,
             typename... States >
   [[nodiscard]] auto match( ParseInput& in, States&&... st )
   {
      if constexpr( !Control< Rule >::enable ) {
         return internal::match_no_control< Rule, A, M, Action, Control >( in, st... );
      }
      else {
         constexpr bool enable_action = ( A == apply_mode::action );

         using iterator_t = typename ParseInput::iterator_t;
         constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const ParseInput&, States... >;
         constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const ParseInput&, States... >;
         constexpr bool has_apply = has_apply_void || has_apply_bool;

         constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const ParseInput&, States... >;
         constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const ParseInput&, States... >;
         constexpr bool has_apply0 = has_apply0_void || has_apply0_bool;

         static_assert( !( has_apply && has_apply0 ), "both apply() and apply0() defined" );

         constexpr bool is_nothing = std::is_base_of_v< nothing< Rule >, Action< Rule > >;
         static_assert( !( has_apply && is_nothing ), "unexpected apply() defined" );
         static_assert( !( has_apply0 && is_nothing ), "unexpected apply0() defined" );

         if constexpr( !has_apply && std::is_base_of_v< require_apply, Action< Rule > > ) {
            internal::missing_apply< Control< Rule >, Action >( in, st... );
         }

         if constexpr( !has_apply0 && std::is_base_of_v< require_apply0, Action< Rule > > ) {
            internal::missing_apply0< Control< Rule >, Action >( in, st... );
         }

         constexpr bool validate_nothing = std::is_base_of_v< maybe_nothing, Action< void > >;
         constexpr bool is_maybe_nothing = std::is_base_of_v< maybe_nothing, Action< Rule > >;
         static_assert( !enable_action || !validate_nothing || is_nothing || is_maybe_nothing || has_apply || has_apply0, "either apply() or apply0() must be defined" );

         constexpr bool use_marker = has_apply || has_apply0_bool;

         auto m = in.template mark< ( use_marker ? rewind_mode::required : rewind_mode::dontcare ) >();
         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
         auto result = internal::match_control_unwind< Rule, A, ( use_marker ? rewind_mode::active : M ), Action, Control >( in, st... );
         if( result ) {
            if constexpr( has_apply_void ) {
               Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
            }
            else if constexpr( has_apply_bool ) {
               result = Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
            }
            else if constexpr( has_apply0_void ) {
               Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
            }
            else if constexpr( has_apply0_bool ) {
               result = Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
            }
         }
         if( result ) {
            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
         }
         else {
            Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
         }
         return m( result );
      }
   }

}  // namespace TAO_PEGTL_NAMESPACE

#if defined( _MSC_VER )
#pragma warning( pop )
#endif

#endif
<commit_msg>Revert simplification<commit_after>// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_MATCH_HPP
#define TAO_PEGTL_MATCH_HPP

#include <type_traits>

#include "apply_mode.hpp"
#include "config.hpp"
#include "nothing.hpp"
#include "require_apply.hpp"
#include "require_apply0.hpp"
#include "rewind_mode.hpp"

#include "internal/has_apply.hpp"
#include "internal/has_apply0.hpp"
#include "internal/has_unwind.hpp"
#include "internal/marker.hpp"
#include "internal/missing_apply.hpp"
#include "internal/missing_apply0.hpp"

#if defined( _MSC_VER )
#pragma warning( push )
#pragma warning( disable : 4702 )
#endif

namespace TAO_PEGTL_NAMESPACE
{
   namespace internal
   {
      template< typename Rule,
                apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename ParseInput,
                typename... States >
      [[nodiscard]] static auto match_no_control( ParseInput& in, States&&... st )
         -> decltype( Rule::template match< A, M, Action, Control >( in, st... ) )
      {
         return Rule::template match< A, M, Action, Control >( in, st... );
      }

      template< typename Rule,
                apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename ParseInput,
                typename... States >
      [[nodiscard]] static auto match_no_control( ParseInput& in, States&&... /*unused*/ )
         -> decltype( Rule::match( in ) )
      {
         return Rule::match( in );
      }

      template< typename Rule,
                apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename ParseInput,
                typename... States >
      [[nodiscard]] auto match_control_unwind( ParseInput& in, States&&... st )
      {
         if constexpr( has_unwind< Control< Rule >, void, const ParseInput&, States... > ) {
            try {
               return match_no_control< Rule, A, M, Action, Control >( in, st... );
            }
            catch( ... ) {
               Control< Rule >::unwind( static_cast< const ParseInput& >( in ), st... );
               throw;
            }
         }
         else {
            return match_no_control< Rule, A, M, Action, Control >( in, st... );
         }
      }

   }  // namespace internal

   template< typename Rule,
             apply_mode A,
             rewind_mode M,
             template< typename... >
             class Action,
             template< typename... >
             class Control,
             typename ParseInput,
             typename... States >
   [[nodiscard]] auto match( ParseInput& in, States&&... st )
   {
      if constexpr( !Control< Rule >::enable ) {
         return internal::match_no_control< Rule, A, M, Action, Control >( in, st... );
      }
      else {
         constexpr bool enable_action = ( A == apply_mode::action );

         using iterator_t = typename ParseInput::iterator_t;
         constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const ParseInput&, States... >;
         constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const ParseInput&, States... >;
         constexpr bool has_apply = has_apply_void || has_apply_bool;

         constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const ParseInput&, States... >;
         constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const ParseInput&, States... >;
         constexpr bool has_apply0 = has_apply0_void || has_apply0_bool;

         static_assert( !( has_apply && has_apply0 ), "both apply() and apply0() defined" );

         constexpr bool is_nothing = std::is_base_of_v< nothing< Rule >, Action< Rule > >;
         static_assert( !( has_apply && is_nothing ), "unexpected apply() defined" );
         static_assert( !( has_apply0 && is_nothing ), "unexpected apply0() defined" );

         if constexpr( !has_apply && std::is_base_of_v< require_apply, Action< Rule > > ) {
            internal::missing_apply< Control< Rule >, Action >( in, st... );
         }

         if constexpr( !has_apply0 && std::is_base_of_v< require_apply0, Action< Rule > > ) {
            internal::missing_apply0< Control< Rule >, Action >( in, st... );
         }

         constexpr bool validate_nothing = std::is_base_of_v< maybe_nothing, Action< void > >;
         constexpr bool is_maybe_nothing = std::is_base_of_v< maybe_nothing, Action< Rule > >;
         static_assert( !enable_action || !validate_nothing || is_nothing || is_maybe_nothing || has_apply || has_apply0, "either apply() or apply0() must be defined" );

         constexpr bool use_marker = has_apply || has_apply0_bool;

         auto m = in.template mark< ( use_marker ? rewind_mode::required : rewind_mode::dontcare ) >();
         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
         auto result = internal::match_control_unwind< Rule, A, ( use_marker ? rewind_mode::active : M ), Action, Control >( in, st... );
         if( result ) {
            if constexpr( has_apply_void ) {
               Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
            }
            else if constexpr( has_apply_bool ) {
               result = Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
            }
            else if constexpr( has_apply0_void ) {
               Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
            }
            else if constexpr( has_apply0_bool ) {
               result = Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
            }
         }
         if( result ) {
            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
         }
         else {
            Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
         }
         (void)m( result );
         return result;
      }
   }

}  // namespace TAO_PEGTL_NAMESPACE

#if defined( _MSC_VER )
#pragma warning( pop )
#endif

#endif
<|endoftext|>