<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   06/04/96

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNtuple                                                              //
//                                                                      //
// A simple tree restricted to a list of float variables only.          //
//                                                                      //
// Each variable goes to a separate branch.                             //
//                                                                      //
//  A Ntuple is created via                                             //
//     TNtuple(name,title,varlist,bufsize)                              //
//  It is filled via:                                                   //
//     TNtuple::Fill(*x)  or                                            //
//     TNtuple::Fill(v1,v2,v3.....)                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TNtuple.h"
#include "TTree.h"
#include "TBranch.h"
#include "TLeaf.h"
#include "TBrowser.h"
#include "Riostream.h"
#include "TClass.h"

#include <string>

ClassImp(TNtuple)

//______________________________________________________________________________
TNtuple::TNtuple(): TTree()
{
//*-*-*-*-*-*Default constructor for Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ==============================

   fNvar = 0;
   fArgs = 0;
}

//______________________________________________________________________________
TNtuple::TNtuple(const char *name, const char *title, const char *varlist, Int_t bufsize)
       :TTree(name,title)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create an Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ================
//       The parameter varlist describes the list of the ntuple variables
//       separated by a colon:
//         example:  "x:y:z:energy"
//       For each variable in the list a separate branch is created.
//
//      NOTE:
//       -Use TTree to create branches with variables of different data types.
//       -Use TTree when the number of branches is large (> 100).
//*-*

   Int_t i;
   fNvar = 0;
   fArgs = 0;

//   Count number of variables (separated by :)
   Int_t nch = strlen(varlist);
   if (nch == 0) return;
   char *vars = new char[nch+1];
   strcpy(vars,varlist);
   Int_t *pvars = new Int_t[nch+1];
   fNvar = 1;
   pvars[0] = 0;
   for (i=1;i<nch;i++) {
      if (vars[i] == ':') {
         pvars[fNvar] = i+1;
         vars[i] = 0;
         fNvar++;
      }
   }
   fArgs = new Float_t[fNvar];

//  Create one branch for each variable
   for (i=0;i<fNvar;i++) {
      Int_t pv = pvars[i];
      TTree::Branch(&vars[pv],&fArgs[i],&vars[pv],bufsize);
   }

   delete [] vars;
   delete [] pvars;
}

//______________________________________________________________________________
TNtuple::~TNtuple()
{
//*-*-*-*-*-*Default destructor for an Ntuple*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ================================

   delete [] fArgs;
   fArgs = 0;
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddress(TBranch *branch)
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   if (branch) {
      Int_t index = fBranches.IndexOf(branch);
      if (index>=0) {
         branch->SetAddress(&fArgs[index]);
      }
   }
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddresses()
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   for (Int_t i = 0; i < fNvar; i++) {
      TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
      if (branch) branch->SetAddress(&fArgs[i]);
   }
}

//______________________________________________________________________________
void TNtuple::Browse(TBrowser *b)
{
   // Browse content of the ntuple

   fLeaves.Browse( b );
}

//______________________________________________________________________________
Int_t TNtuple::Fill()
{
//*-*-*-*-*-*-*-*-*Fill a Ntuple with current values in fArgs*-*-*-*-*-*-*
//*-*              ==========================================
// Note that this function is protected.
// Currently called only by TChain::Merge

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(const Float_t *x)
{
   // Fill a Ntuple with an array of floats

   // Store array x into buffer
   for (Int_t i=0;i<fNvar;i++)  {
      fArgs[i] = x[i];
   }

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(Float_t x0,Float_t x1,Float_t x2,Float_t x3,Float_t x4
              ,Float_t x5,Float_t x6,Float_t x7,Float_t x8,Float_t x9
              ,Float_t x10,Float_t x11,Float_t x12,Float_t x13,Float_t x14)
{
   // Fill a Ntuple: Each Ntuple item is an argument

   if (fNvar >  0) fArgs[0]  = x0;
   if (fNvar >  1) fArgs[1]  = x1;
   if (fNvar >  2) fArgs[2]  = x2;
   if (fNvar >  3) fArgs[3]  = x3;
   if (fNvar >  4) fArgs[4]  = x4;
   if (fNvar >  5) fArgs[5]  = x5;
   if (fNvar >  6) fArgs[6]  = x6;
   if (fNvar >  7) fArgs[7]  = x7;
   if (fNvar >  8) fArgs[8]  = x8;
   if (fNvar >  9) fArgs[9]  = x9;
   if (fNvar > 10) fArgs[10] = x10;
   if (fNvar > 11) fArgs[11] = x11;
   if (fNvar > 12) fArgs[12] = x12;
   if (fNvar > 13) fArgs[13] = x13;
   if (fNvar > 14) fArgs[14] = x14;

   return TTree::Fill();
}

//_______________________________________________________________________
Long64_t TNtuple::ReadFile(const char *filename, const char * /*branchDescriptor*/)
{
   // Read from filename as many columns as variables in the ntuple
   // the function returns the number of rows found in the file
   // The second argument "branchDescriptor" is currently not used.
   // Lines in the input file starting with "#" are ignored.

   Long64_t nlines = 0;
   ifstream in;
   in.open(filename);
   while (1) {
      if ( in.peek() != '#' ) {
         for (Int_t i=0;i<fNvar;i++) in >> fArgs[i];
         if (!in.good()) break;
         TTree::Fill();
         nlines++;
      }
      in.ignore(8192,'\n');
   }
   in.close();
   return nlines;
}

//_______________________________________________________________________
void TNtuple::Streamer(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*              =========================================
   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         b.ReadClassBuffer(TNtuple::Class(), this, R__v, R__s, R__c);
      } else {
         //====process old versions before automatic schema evolution
         TTree::Streamer(b);
         b >> fNvar;
         b.CheckByteCount(R__s, R__c, TNtuple::IsA());
         //====end of old versions
      }
      if (fNvar <= 0) return;
      fArgs = new Float_t[fNvar];
      for (Int_t i=0;i<fNvar;i++) {
         TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
         if (branch) branch->SetAddress(&fArgs[i]);
      }
   } else {
      b.WriteClassBuffer(TNtuple::Class(),this);
   }
}
<commit_msg>replace calls to strcpy by strncpy<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   06/04/96

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNtuple                                                              //
//                                                                      //
// A simple tree restricted to a list of float variables only.          //
//                                                                      //
// Each variable goes to a separate branch.                             //
//                                                                      //
//  A Ntuple is created via                                             //
//     TNtuple(name,title,varlist,bufsize)                              //
//  It is filled via:                                                   //
//     TNtuple::Fill(*x)  or                                            //
//     TNtuple::Fill(v1,v2,v3.....)                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TNtuple.h"
#include "TTree.h"
#include "TBranch.h"
#include "TLeaf.h"
#include "TBrowser.h"
#include "Riostream.h"
#include "TClass.h"

#include <string>

ClassImp(TNtuple)

//______________________________________________________________________________
TNtuple::TNtuple(): TTree()
{
//*-*-*-*-*-*Default constructor for Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ==============================

   fNvar = 0;
   fArgs = 0;
}

//______________________________________________________________________________
TNtuple::TNtuple(const char *name, const char *title, const char *varlist, Int_t bufsize)
       :TTree(name,title)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create an Ntuple*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ================
//       The parameter varlist describes the list of the ntuple variables
//       separated by a colon:
//         example:  "x:y:z:energy"
//       For each variable in the list a separate branch is created.
//
//      NOTE:
//       -Use TTree to create branches with variables of different data types.
//       -Use TTree when the number of branches is large (> 100).
//*-*

   Int_t i;
   fNvar = 0;
   fArgs = 0;

//   Count number of variables (separated by :)
   Int_t nch = strlen(varlist);
   if (nch == 0) return;
   char *vars = new char[nch+1];
   strncpy(vars,varlist,nch);
   Int_t *pvars = new Int_t[nch+1];
   fNvar = 1;
   pvars[0] = 0;
   for (i=1;i<nch;i++) {
      if (vars[i] == ':') {
         pvars[fNvar] = i+1;
         vars[i] = 0;
         fNvar++;
      }
   }
   fArgs = new Float_t[fNvar];

//  Create one branch for each variable
   for (i=0;i<fNvar;i++) {
      Int_t pv = pvars[i];
      TTree::Branch(&vars[pv],&fArgs[i],&vars[pv],bufsize);
   }

   delete [] vars;
   delete [] pvars;
}

//______________________________________________________________________________
TNtuple::~TNtuple()
{
//*-*-*-*-*-*Default destructor for an Ntuple*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ================================

   delete [] fArgs;
   fArgs = 0;
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddress(TBranch *branch)
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   if (branch) {
      Int_t index = fBranches.IndexOf(branch);
      if (index>=0) {
         branch->SetAddress(&fArgs[index]);
      }
   }
}

//______________________________________________________________________________
void TNtuple::ResetBranchAddresses()
{
   // Reset the branch addresses to the internal fArgs array. Use this
   // method when the addresses were changed via calls to SetBranchAddress().

   for (Int_t i = 0; i < fNvar; i++) {
      TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
      if (branch) branch->SetAddress(&fArgs[i]);
   }
}

//______________________________________________________________________________
void TNtuple::Browse(TBrowser *b)
{
   // Browse content of the ntuple

   fLeaves.Browse( b );
}

//______________________________________________________________________________
Int_t TNtuple::Fill()
{
//*-*-*-*-*-*-*-*-*Fill a Ntuple with current values in fArgs*-*-*-*-*-*-*
//*-*              ==========================================
// Note that this function is protected.
// Currently called only by TChain::Merge

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(const Float_t *x)
{
   // Fill a Ntuple with an array of floats

   // Store array x into buffer
   for (Int_t i=0;i<fNvar;i++)  {
      fArgs[i] = x[i];
   }

   return TTree::Fill();
}

//______________________________________________________________________________
Int_t TNtuple::Fill(Float_t x0,Float_t x1,Float_t x2,Float_t x3,Float_t x4
              ,Float_t x5,Float_t x6,Float_t x7,Float_t x8,Float_t x9
              ,Float_t x10,Float_t x11,Float_t x12,Float_t x13,Float_t x14)
{
   // Fill a Ntuple: Each Ntuple item is an argument

   if (fNvar >  0) fArgs[0]  = x0;
   if (fNvar >  1) fArgs[1]  = x1;
   if (fNvar >  2) fArgs[2]  = x2;
   if (fNvar >  3) fArgs[3]  = x3;
   if (fNvar >  4) fArgs[4]  = x4;
   if (fNvar >  5) fArgs[5]  = x5;
   if (fNvar >  6) fArgs[6]  = x6;
   if (fNvar >  7) fArgs[7]  = x7;
   if (fNvar >  8) fArgs[8]  = x8;
   if (fNvar >  9) fArgs[9]  = x9;
   if (fNvar > 10) fArgs[10] = x10;
   if (fNvar > 11) fArgs[11] = x11;
   if (fNvar > 12) fArgs[12] = x12;
   if (fNvar > 13) fArgs[13] = x13;
   if (fNvar > 14) fArgs[14] = x14;

   return TTree::Fill();
}

//_______________________________________________________________________
Long64_t TNtuple::ReadFile(const char *filename, const char * /*branchDescriptor*/)
{
   // Read from filename as many columns as variables in the ntuple
   // the function returns the number of rows found in the file
   // The second argument "branchDescriptor" is currently not used.
   // Lines in the input file starting with "#" are ignored.

   Long64_t nlines = 0;
   ifstream in;
   in.open(filename);
   while (1) {
      if ( in.peek() != '#' ) {
         for (Int_t i=0;i<fNvar;i++) in >> fArgs[i];
         if (!in.good()) break;
         TTree::Fill();
         nlines++;
      }
      in.ignore(8192,'\n');
   }
   in.close();
   return nlines;
}

//_______________________________________________________________________
void TNtuple::Streamer(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*              =========================================
   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         b.ReadClassBuffer(TNtuple::Class(), this, R__v, R__s, R__c);
      } else {
         //====process old versions before automatic schema evolution
         TTree::Streamer(b);
         b >> fNvar;
         b.CheckByteCount(R__s, R__c, TNtuple::IsA());
         //====end of old versions
      }
      if (fNvar <= 0) return;
      fArgs = new Float_t[fNvar];
      for (Int_t i=0;i<fNvar;i++) {
         TBranch *branch = (TBranch*)fBranches.UncheckedAt(i);
         if (branch) branch->SetAddress(&fArgs[i]);
      }
   } else {
      b.WriteClassBuffer(TNtuple::Class(),this);
   }
}
<|endoftext|>


<commit_before>#include "optionshierarchy.h"
#include "io.h"
#include <string>
#include <iostream>
#include <sys/time.h>
#include <typeinfo>

#define DEFAULT_INT 42

#define BOOST_TEST_MODULE Something
#include <boost/test/unit_test.hpp>

using namespace mlpack;

/*
PROGRAM_INFO("MLPACK IO Test",
  "This is a simple test of the IO framework for input options and timers.  "
  "This particular text can be seen if you type --help.")

PARAM(int, "gint", "global desc", "global", 42, false);
PARAM(int, "req", "required", "global", 23, true);
PARAM_INT("something_long_long_long", "A particularly long and needlessly "
  "verbose description ensures that my line hyphenator is working correctly "
  "but to test we need a "
  "really_really_really_long_long_long_long_long_long_long_long_word.", "",
  10);
*/

/**
* @brief Tests that inserting elements into an OptionsHierarchy
*   properly updates the tree.
*
* @return True indicating all is well with OptionsHierarchy
*/

namespace mlpack {
namespace io {

BOOST_AUTO_TEST_CASE(TestHierarchy) {
  OptionsHierarchy tmp = OptionsHierarchy("UTest");

  std::string testName = std::string("UTest/test");
  std::string testDesc = std::string("Test description.");
  std::string testTID = TYPENAME(int);

  //Check that the hierarchy is properly named.
  std::string str = std::string("UTest");
  OptionsData node = tmp.GetNodeData();

  BOOST_REQUIRE_EQUAL(str.compare(node.node), 0);

  //Check that inserting a node actually inserts the node.
  // Note, that since all versions of append simply call the most qualified
  //    overload, we will only test that one.
  tmp.AppendNode(testName, testTID, testDesc);
  BOOST_REQUIRE(tmp.FindNode(testName) != NULL);

  //Now check that the inserted node has the correct data.
  OptionsHierarchy* testHierarchy = tmp.FindNode(testName);
  OptionsData testData;
  if (testHierarchy != NULL) {
    node = testHierarchy->GetNodeData();

    BOOST_REQUIRE(testName.compare(node.node) == 0);
    BOOST_REQUIRE(testDesc.compare(node.desc) == 0);
    BOOST_REQUIRE(testTID.compare(node.tname) == 0);

  } else {}
}
}
}

/**
* @brief Tests that IO works as intended, namely that IO::Add
*   propogates successfully.
*
* @return True indicating all is well with IO, false otherwise.
*/
BOOST_AUTO_TEST_CASE(TestIO) {
  //  BOOST_REQUIRE_CLOSE(IO::GetParam<int>("global/gint") + 1e-6,
  //   DEFAULT_INT + 1e-6, 1e-5);

  //Check that the IO::HasParam returns false if no value has been specified
  //On the commandline or programmatically.
  IO::Add<bool>("bool", "True or False", "global");

  BOOST_REQUIRE_EQUAL(IO::HasParam("global/bool"), false);

  IO::GetParam<bool>("global/bool") = true;

  //IO::HasParam should return true now.
  BOOST_REQUIRE_EQUAL(IO::HasParam("global/bool"), true);

  BOOST_REQUIRE_EQUAL(IO::GetDescription("global/bool").compare(
                              std::string("True or False")) , 0);

  //Check that SanitizeString is sanitary.
  std::string tmp = IO::SanitizeString("/foo/bar/fizz");
  BOOST_REQUIRE_EQUAL(tmp.compare(std::string("foo/bar/fizz/")),0);

  //Now lets test the output functions.  Will have to eyeball it manually.
  IO::Debug << "Test the new lines...";
  IO::Debug << "shouldn't get 'Info' here." << std::endl;
  IO::Debug << "But now I should." << std::endl << std::endl;

  //Test IO::Debug
  IO::Debug << "You shouldn't see this when DEBUG=OFF" << std::endl;

}

/**
* @brief Tests that the various PARAM_* macros work properly
* @return True indicating that all is well with IO & Options.
*/
BOOST_AUTO_TEST_CASE(TestOption) {
  //This test will involve creating an option, and making sure IO reflects this.
  PARAM(int, "test", "test desc", "test_parent", DEFAULT_INT, false);

  //Does IO reflect this?
  BOOST_REQUIRE_EQUAL(IO::HasParam("test_parent/test"), true);

  std::string desc = std::string("test desc");

  BOOST_REQUIRE(desc.compare(IO::GetDescription("test_parent/test"))==0);
  BOOST_REQUIRE(IO::GetParam<int>("test_parent/test") == DEFAULT_INT);
}

<commit_msg>-- FX Conversion to Boost Unit Test<commit_after>#include "optionshierarchy.h"
#include "io.h"
#include <string>
#include <iostream>
#include <sys/time.h>
#include <typeinfo>

#define DEFAULT_INT 42

#define BOOST_TEST_MODULE Something
#include <boost/test/unit_test.hpp>

using namespace mlpack;

/*
PROGRAM_INFO("MLPACK IO Test",
  "This is a simple test of the IO framework for input options and timers.  "
  "This particular text can be seen if you type --help.")

PARAM(int, "gint", "global desc", "global", 42, false);
PARAM(int, "req", "required", "global", 23, true);
PARAM_INT("something_long_long_long", "A particularly long and needlessly "
  "verbose description ensures that my line hyphenator is working correctly "
  "but to test we need a "
  "really_really_really_long_long_long_long_long_long_long_long_word.", "",
  10);
*/

/**
* @brief Tests that inserting elements into an OptionsHierarchy
*   properly updates the tree.
*
* @return True indicating all is well with OptionsHierarchy
*/

namespace mlpack {
namespace io {

BOOST_AUTO_TEST_CASE(TestHierarchy) {
  OptionsHierarchy tmp = OptionsHierarchy("UTest");

  std::string testName = std::string("UTest/test");
  std::string testDesc = std::string("Test description.");
  std::string testTID = TYPENAME(int);

  //Check that the hierarchy is properly named.
  std::string str = std::string("UTest");
  OptionsData node = tmp.GetNodeData();

  BOOST_REQUIRE_EQUAL(str.compare(node.node), 0);

  //Check that inserting a node actually inserts the node.
  // Note, that since all versions of append simply call the most qualified
  //    overload, we will only test that one.
  tmp.AppendNode(testName, testTID, testDesc);
  BOOST_REQUIRE(tmp.FindNode(testName) != NULL);

  //Now check that the inserted node has the correct data.
  OptionsHierarchy* testHierarchy = tmp.FindNode(testName);
  OptionsData testData;
  if (testHierarchy != NULL) {
    node = testHierarchy->GetNodeData();

    BOOST_REQUIRE(testName.compare(node.node) == 0);
    BOOST_REQUIRE(testDesc.compare(node.desc) == 0);
    BOOST_REQUIRE(testTID.compare(node.tname) == 0);

  } else {}
}
}
}

/**
* @brief Tests that IO works as intended, namely that IO::Add
*   propogates successfully.
*
* @return True indicating all is well with IO, false otherwise.
*/
BOOST_AUTO_TEST_CASE(TestIO) {
  //  BOOST_REQUIRE_CLOSE(IO::GetParam<int>("global/gint") + 1e-6,
  //   DEFAULT_INT + 1e-6, 1e-5);

  //Check that the IO::HasParam returns false if no value has been specified
  //On the commandline or programmatically.
  IO::Add<bool>("bool", "True or False", "global");

  BOOST_REQUIRE_EQUAL(IO::HasParam("global/bool"), false);

  IO::GetParam<bool>("global/bool") = true;

  //IO::HasParam should return true now.
  BOOST_REQUIRE_EQUAL(IO::HasParam("global/bool"), true);

  BOOST_REQUIRE_EQUAL(IO::GetDescription("global/bool").compare(
                              std::string("True or False")) , 0);

  //Check that SanitizeString is sanitary.
  std::string tmp = IO::SanitizeString("/foo/bar/fizz");
  BOOST_REQUIRE_EQUAL(tmp.compare(std::string("foo/bar/fizz/")),0);

/*
  //Now lets test the output functions.  Will have to eyeball it manually.
  IO::Debug << "Test the new lines...";
  IO::Debug << "shouldn't get 'Info' here." << std::endl;
  IO::Debug << "But now I should." << std::endl << std::endl;

  //Test IO::Debug
  IO::Debug << "You shouldn't see this when DEBUG=OFF" << std::endl;
*/

}

/**
* @brief Tests that the various PARAM_* macros work properly
* @return True indicating that all is well with IO & Options.
*/
BOOST_AUTO_TEST_CASE(TestOption) {
  //This test will involve creating an option, and making sure IO reflects this.
  PARAM(int, "test", "test desc", "test_parent", DEFAULT_INT, false);

  //Does IO reflect this?
  BOOST_REQUIRE_EQUAL(IO::HasParam("test_parent/test"), true);

  std::string desc = std::string("test desc");

  BOOST_REQUIRE(desc.compare(IO::GetDescription("test_parent/test"))==0);
  BOOST_REQUIRE(IO::GetParam<int>("test_parent/test") == DEFAULT_INT);
}

<|endoftext|>


<commit_before>// CppUnit
#include "cppunit/extensions/HelperMacros.h"
#include "cppunit/ui/text/TestRunner.h"
#include "cppunit/TestAssert.h"
// STL
#include <string>

#include "GpuTypes.h"
#include "NNTypes.h"
#include "kernels.h"
#include "Utils.h"

using namespace std;

void randData(NNFloat* pTarget, NNFloat* pOut, const size_t batch, const size_t nFeatures, const size_t stride) {
  memset(pTarget, 0, stride * batch * sizeof(NNFloat));
  memset(pOut, 0, stride * batch * sizeof(NNFloat));
  for (size_t i = 0; i < batch; i++) {

    for (size_t k = 0; k < nFeatures; k++) {
      pTarget[k] = rand(0, nFeatures - 1);
    }

    for (size_t o = 0; o < nFeatures; o++) {
      pOut[o] = rand(0.f, 1.f);
    }

    pTarget += stride;
    pOut += stride;
  }
}

bool testTopK(const size_t batch = 128, const size_t topK = 128, const size_t nFeatures = 1024) {

  cout << "TEST kCalculateTopK with parameters: " << "batch=" << batch << " topK=" << topK << " nFeatures=" << nFeatures << endl;
  bool ret = true;

  const float EPS = 1.e-6;
  const size_t STRIDE = ((nFeatures + 127) >> 7) << 7;
  timeval t0, t1;

  // allocate memory same way with main engine
  GpuBuffer<NNFloat>* pbKey = new GpuBuffer<NNFloat>(batch * topK, true);
  GpuBuffer<NNFloat>* pbFValue = new GpuBuffer<NNFloat>(batch * topK, true);
  GpuBuffer<unsigned int>* pbUIValue = new GpuBuffer<unsigned int>(batch * topK, true);

  GpuBuffer<NNFloat>* pbTarget = new GpuBuffer<NNFloat>(batch * STRIDE, true);
  GpuBuffer<NNFloat>* pbOutput = new GpuBuffer<NNFloat>(batch * STRIDE, true);

  cout << "1 TEST kCalculateTopK with 3 args" << endl;

  // prepare data
  {
    NNFloat* pTarget = pbTarget->_pSysData;
    NNFloat* pOut = pbOutput->_pSysData; // data from output layer (scores)

    randData(pTarget, pOut, batch, nFeatures, STRIDE);

    pbTarget->Upload(); // desired output
    pbOutput->Upload(); // copy of output layer + filtering

    memset(pbUIValue->_pSysData, 0, batch * topK * sizeof(unsigned int));
    pbUIValue->Upload();
  }
  // run test 1
  gettimeofday(&t0, NULL);
  kCalculateTopK(pbOutput->_pDevData, pbKey->_pDevData, pbUIValue->_pDevData, batch, STRIDE, topK);
  gettimeofday(&t1, NULL);
  cout << "GPU sort: " << elapsed_time(t1, t0) << endl;

  //validate data
  {
    pbOutput->Download();
    pbTarget->Download();
    pbKey->Download();
    pbFValue->Download();
    pbUIValue->Download();

    vector<float> keys(nFeatures);
    vector<unsigned int> topK_vals(topK);
    vector<float> topK_keys(topK);

    NNFloat* pOutput = pbOutput->_pSysData;
    NNFloat* pKey = pbKey->_pSysData;
    unsigned int* pUIValue = pbUIValue->_pSysData;

    int countValueError = 0;
    float sumKeyError = 0.f;
    float cpuSort = 0.f;

    for (size_t i = 0; i < batch; i++) {

      gettimeofday(&t0, NULL);
      topKsort<NNFloat, unsigned int>(pOutput, NULL, nFeatures, &topK_keys[0], &topK_vals[0], topK);
      gettimeofday(&t1, NULL);
      cpuSort += elapsed_time(t1, t0);

      for (size_t k = 0; k < topK; k++) {
        unsigned int GPUvalue = pUIValue[k]; // index
        float GPUkey = pKey[k]; // score

        float CPUvalue = topK_vals[k];
        float CPUkey = topK_keys[k];

        if (fabs(GPUvalue - CPUvalue) > EPS) {
          countValueError++;
        }
        sumKeyError += fabs(GPUkey - CPUkey);
      }
      pKey += topK;
      pUIValue += topK;
      pOutput += STRIDE;
    }
    cout << "CPU sort: " << cpuSort << endl;

    if (countValueError && sumKeyError) {
      cout << "1 ERROR kCalculateTopK with 3 args; ";
      ret = false;
    } else {
      cout << "1 PASS kCalculateTopK with 3 args; "; // some error is accepted because bitonic sort belongs to not stable sorting
    }
    cout << "countValueError " << countValueError << " sumKeyError " << sumKeyError << endl;
  }

  cout << "2 TEST kCalculateTopK with 4 args" << endl;

  // prepare data
  {
    NNFloat* pTarget = pbTarget->_pSysData;
    NNFloat* pOut = pbOutput->_pSysData; // data from output layer (scores)

    randData(pTarget, pOut, batch, nFeatures, STRIDE);

    pbTarget->Upload(); // desired output
    pbOutput->Upload(); // copy of output layer + filtering
  }

  //run test
  kCalculateTopK(pbOutput->_pDevData, pbTarget->_pDevData, pbKey->_pDevData, pbFValue->_pDevData, batch, STRIDE, topK);

  //validate data
  {
    pbOutput->Download();
    pbTarget->Download();
    pbKey->Download();
    pbFValue->Download();

    vector<float> vals(nFeatures);
    vector<float> keys(nFeatures);
    vector<float> topK_vals(topK);
    vector<float> topK_keys(topK);

    NNFloat* pOutput = pbOutput->_pSysData;
    NNFloat* pTarget = pbTarget->_pSysData;
    NNFloat* pKey = pbKey->_pSysData;
    NNFloat* pValue = pbFValue->_pSysData;

    int countValueError = 0;
    float sumKeyError = 0;

    for (size_t i = 0; i < batch; i++) {

      topKsort<NNFloat, NNFloat>(pOutput, pTarget, nFeatures, &topK_keys[0], &topK_vals[0], topK);

      for (size_t k = 0; k < topK; k++) {
        unsigned int GPUvalue = pValue[k]; // index
        float GPUkey = pKey[k]; // score

        float CPUvalue = topK_vals[k];
        float CPUkey = topK_keys[k];

        if (fabs(GPUvalue - CPUvalue) > EPS) {
          countValueError++;
        }
        sumKeyError += fabs(GPUkey - CPUkey);
      }
      pKey += topK;
      pValue += topK;
      pOutput += STRIDE;
      pTarget += STRIDE;
    }

    if (countValueError && sumKeyError) {
      cout << "2 ERROR kCalculateTopK with 4 args; ";
      ret = false;
    } else {
      cout << "2 PASS kCalculateTopK with 4 args; ";
    }
    cout << "countValueError " << countValueError << " sumKeyError " << sumKeyError << endl;
  }

  int totalGPUMemory;
  int totalCPUMemory;
  getGpu().GetMemoryUsage(&totalGPUMemory, &totalCPUMemory);
  cout << "GPU Memory Usage: " << totalGPUMemory << " KB" << endl;
  cout << "CPU Memory Usage: " << totalCPUMemory << " KB" << endl;

  delete pbKey;
  delete pbFValue;
  delete pbTarget;
  delete pbOutput;
  delete pbUIValue;

  return ret;
}

//----------------------------------------------------------------------------
class TestSort : public CppUnit::TestFixture
{
public:             // Interface
    void            TestCPU_GPUSort()
    {
      {
        const size_t BATCH = 128;
        const size_t TOP_K = 128;
        const size_t N_FEATURES = 1024;
        bool result = testTopK(BATCH, TOP_K, N_FEATURES);
        CPPUNIT_ASSERT_MESSAGE("failed with N_FEATURES = 1024, TOP_K = 128", result);
      }
      {
        const size_t BATCH = 128;
        const size_t TOP_K = 128;
        const size_t N_FEATURES = 100000;
        bool result = testTopK(BATCH, TOP_K, N_FEATURES);
        CPPUNIT_ASSERT_MESSAGE("failed with N_FEATURES = 100000, TOP_K = 128", result);
      }
      {
        const size_t BATCH = 128;
        const size_t TOP_K = 64;
        const size_t N_FEATURES = 1024;
        bool result = testTopK(BATCH, TOP_K, N_FEATURES);
        CPPUNIT_ASSERT_MESSAGE("failed with N_FEATURES = 1024, TOP_K = 64", result);
      }
      {
        const size_t BATCH = 128;
        const size_t TOP_K = 32;
        const size_t N_FEATURES = 64;
        bool result = testTopK(BATCH, TOP_K, N_FEATURES);
        CPPUNIT_ASSERT_MESSAGE("failed with N_FEATURES = 64, TOP_K = 32", result);
      }
      {
        const size_t BATCH = 128;
        const size_t TOP_K = 1;
        const size_t N_FEATURES = 64;
        bool result = testTopK(BATCH, TOP_K, N_FEATURES);
        CPPUNIT_ASSERT_MESSAGE("failed with N_FEATURES = 64, TOP_K = 32", result);
      }
    }

public:
    CPPUNIT_TEST_SUITE(TestSort);
    CPPUNIT_TEST(TestCPU_GPUSort);
    CPPUNIT_TEST_SUITE_END();

};
<commit_msg>refactor sort test<commit_after>// CppUnit
#include "cppunit/extensions/HelperMacros.h"
#include "cppunit/ui/text/TestRunner.h"
#include "cppunit/TestAssert.h"
// STL
#include <string>

#include "GpuTypes.h"
#include "NNTypes.h"
#include "kernels.h"
#include "Utils.h"

void randData(NNFloat* pTarget, NNFloat* pOut, const size_t batch, const size_t nFeatures, const size_t stride) {
    memset(pTarget, 0, stride * batch * sizeof(NNFloat));
    memset(pOut, 0, stride * batch * sizeof(NNFloat));
    for (size_t i = 0; i < batch; i++) {

        for (size_t k = 0; k < nFeatures; k++) {
            pTarget[k] = rand(0, nFeatures - 1);
        }

        for (size_t o = 0; o < nFeatures; o++) {
            pOut[o] = rand(0.f, 1.f);
        }

        pTarget += stride;
        pOut += stride;
    }
}

bool testTopK(const size_t batch = 128, const size_t topK = 128, const size_t nFeatures = 1024) {

    cout << "TEST kCalculateTopK with parameters: " << "batch=" << batch << " topK=" << topK << " nFeatures=" << nFeatures << endl;
    bool ret = true;

    const float eps = 1.e-6;
    const size_t stride = ((nFeatures + 127) >> 7) << 7;
    timeval t0, t1;

    std::unique_ptr<GpuBuffer<NNFloat> > pbKey(new GpuBuffer<NNFloat>(batch * topK, true));
    std::unique_ptr<GpuBuffer<NNFloat> > pbFValue(new GpuBuffer<NNFloat>(batch * topK, true));
    std::unique_ptr<GpuBuffer<unsigned int> > pbUIValue( new GpuBuffer<unsigned int>(batch * topK, true));

    std::unique_ptr<GpuBuffer<NNFloat> > pbTarget( new GpuBuffer<NNFloat>(batch * stride, true));
    std::unique_ptr<GpuBuffer<NNFloat> > pbOutput(new GpuBuffer<NNFloat>(batch * stride, true));

    cout << "1 TEST kCalculateTopK with 3 args" << endl;

    // prepare data
    {
        NNFloat* pTarget = pbTarget->_pSysData;
        NNFloat* pOut = pbOutput->_pSysData; // data from output layer (scores)

        randData(pTarget, pOut, batch, nFeatures, stride);

        pbTarget->Upload(); // desired output
        pbOutput->Upload(); // copy of output layer + filtering

        memset(pbUIValue->_pSysData, 0, batch * topK * sizeof(unsigned int));
        pbUIValue->Upload();
    }
    // run test 1
    gettimeofday(&t0, NULL);
    kCalculateTopK(pbOutput->_pDevData, pbKey->_pDevData, pbUIValue->_pDevData, batch, stride, topK);
    gettimeofday(&t1, NULL);
    cout << "GPU sort: " << elapsed_time(t1, t0) << endl;

    //validate data
    {
        pbOutput->Download();
        pbTarget->Download();
        pbKey->Download();
        pbFValue->Download();
        pbUIValue->Download();

        vector<float> keys(nFeatures);
        vector<unsigned int> topKvals(topK);
        vector<float> topKkeys(topK);

        NNFloat* pOutput = pbOutput->_pSysData;
        NNFloat* pKey = pbKey->_pSysData;
        unsigned int* pUIValue = pbUIValue->_pSysData;

        int countValueError = 0;
        float sumKeyError = 0.f;
        float cpuSort = 0.f;

        for (size_t i = 0; i < batch; i++) {

            gettimeofday(&t0, NULL);
            topKsort<NNFloat, unsigned int>(pOutput, NULL, nFeatures, &topKkeys[0], &topKvals[0], topK);
            gettimeofday(&t1, NULL);
            cpuSort += elapsed_time(t1, t0);

            for (size_t k = 0; k < topK; k++) {
                unsigned int GPUvalue = pUIValue[k]; // index
                float GPUkey = pKey[k]; // score

                float CPUvalue = topKvals[k];
                float CPUkey = topKkeys[k];

                if (fabs(GPUvalue - CPUvalue) > eps) {
                    countValueError++;
                }
                sumKeyError += fabs(GPUkey - CPUkey);
            }
            pKey += topK;
            pUIValue += topK;
            pOutput += stride;
        }
        cout << "CPU sort: " << cpuSort << endl;

        if (countValueError && sumKeyError) {
            cout << "1 ERROR kCalculateTopK with 3 args; ";
            ret = false;
        } else {
            cout << "1 PASS kCalculateTopK with 3 args; "; // some error is accepted because bitonic sort belongs to not stable sorting
        }
        cout << "countValueError " << countValueError << " sumKeyError " << sumKeyError << endl;
    }

    cout << "2 TEST kCalculateTopK with 4 args" << endl;

    // prepare data
    {
        NNFloat* pTarget = pbTarget->_pSysData;
        NNFloat* pOut = pbOutput->_pSysData; // data from output layer (scores)

        randData(pTarget, pOut, batch, nFeatures, stride);

        pbTarget->Upload(); // desired output
        pbOutput->Upload(); // copy of output layer + filtering
    }

    //run test
    kCalculateTopK(pbOutput->_pDevData, pbTarget->_pDevData, pbKey->_pDevData, pbFValue->_pDevData, batch, stride, topK);

    //validate data
    {
        pbOutput->Download();
        pbTarget->Download();
        pbKey->Download();
        pbFValue->Download();

        vector<float> vals(nFeatures);
        vector<float> keys(nFeatures);
        vector<float> topKvals(topK);
        vector<float> topKkeys(topK);

        NNFloat* pOutput = pbOutput->_pSysData;
        NNFloat* pTarget = pbTarget->_pSysData;
        NNFloat* pKey = pbKey->_pSysData;
        NNFloat* pValue = pbFValue->_pSysData;

        int countValueError = 0;
        float sumKeyError = 0;

        for (size_t i = 0; i < batch; i++) {

            topKsort<NNFloat, NNFloat>(pOutput, pTarget, nFeatures, &topKkeys[0], &topKvals[0], topK);

            for (size_t k = 0; k < topK; k++) {
                unsigned int GPUvalue = pValue[k]; // index
                float GPUkey = pKey[k]; // score

                float CPUvalue = topKvals[k];
                float CPUkey = topKkeys[k];

                if (fabs(GPUvalue - CPUvalue) > eps) {
                    countValueError++;
                }
                sumKeyError += fabs(GPUkey - CPUkey);
            }
            pKey += topK;
            pValue += topK;
            pOutput += stride;
            pTarget += stride;
        }

        if (countValueError && sumKeyError) {
            cout << "2 ERROR kCalculateTopK with 4 args; ";
            ret = false;
        } else {
            cout << "2 PASS kCalculateTopK with 4 args; ";
        }
        cout << "countValueError " << countValueError << " sumKeyError " << sumKeyError << endl;
    }

    int totalGPUMemory;
    int totalCPUMemory;
    getGpu().GetMemoryUsage(&totalGPUMemory, &totalCPUMemory);
    cout << "GPU Memory Usage: " << totalGPUMemory << " KB" << endl;
    cout << "CPU Memory Usage: " << totalCPUMemory << " KB" << endl;

    return ret;
}

//----------------------------------------------------------------------------
class TestSort: public CppUnit::TestFixture {
public:
    // Interface
    void TestCPU_GPUSort() {
        // Initialize GPU
        getGpu().SetRandomSeed(12345);
        getGpu().CopyConstants();
        const size_t numberTests = 5;
        const size_t batches[numberTests] =        {128,  128,    128,  128, 128};
        const size_t topK[numberTests] =           {128,  128,    64,   32,  1};
        const size_t numberFeatures[numberTests] = {1024, 100000, 1024, 64,  64};

        for (size_t i = 0; i < numberTests; i++) {
            bool result = testTopK(batches[i], topK[i], numberFeatures[i]);
            cout << "batches " << batches[i] <<  ", topK " << topK[i] << ", numberFeatures" << numberFeatures[i] << endl;
            CPPUNIT_ASSERT_MESSAGE("failed gpuSort", result);
        }
    }

public:
    CPPUNIT_TEST_SUITE(TestSort);
    CPPUNIT_TEST(TestCPU_GPUSort);
    CPPUNIT_TEST_SUITE_END();
};
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_eve
/// Demonstrates usage of simple configuration via TEveParamList class.
///
/// \macro_code
///
/// \author Matevz Tadel

#include "TEveManager.h"
#include "TEveParamList.h"
#include "TQObject.h"

class TParamFollower
{
public:
   TParamFollower()
   {
      TQObject::Connect("TEveParamList", "ParamChanged(char*)",
                        "TParamFollower", this, "OnParamChanged(char*)");
   }
   virtual ~TParamFollower()
   {
      TQObject::Disconnect("TParamFollower", "ParamChanged(char*)",
                           this, "OnParamChanged(char*)");
   }

   void OnParamChanged(const char* parameter)
   {
      TEveParamList* pl = dynamic_cast<TEveParamList*>
         (reinterpret_cast<TQObject*>(gTQSender));

      printf("Change in param-list '%s', parameter '%s'.\n",
             pl->GetElementName(), parameter);
   }

   ClassDef(TParamFollower, 0);
};

ClassImp(TParamFollower)

void paramlist()
{
   TEveManager::Create();

   TEveParamList* x = 0;

   x = new TEveParamList("Top config");
   gEve->AddToListTree(x, 0);

   x->AddParameter(TEveParamList::FloatConfig_t("Pepe", 20, 0, 110));
   x->AddParameter(TEveParamList::IntConfig_t("Dima", 100, 0, 110));
   x->AddParameter(TEveParamList::BoolConfig_t("Chris", 1));

   x = new TEveParamList("Another config");
   gEve->AddToListTree(x, 0);

   x->AddParameter(TEveParamList::FloatConfig_t("MagneticField", 4, -4, 4));
   x->AddParameter(TEveParamList::FloatConfig_t("Temperature", 16, -20, 40));

   new TParamFollower;
}
<commit_msg>- use auto - formatting<commit_after>/// \file
/// \ingroup tutorial_eve
/// Demonstrates usage of simple configuration via TEveParamList class.
///
/// \macro_code
///
/// \author Matevz Tadel

#include "TEveManager.h"
#include "TEveParamList.h"
#include "TQObject.h"

class TParamFollower
{
public:
   TParamFollower()
   {
      TQObject::Connect("TEveParamList", "ParamChanged(char*)",
                        "TParamFollower", this, "OnParamChanged(char*)");
   }
   virtual ~TParamFollower()
   {
      TQObject::Disconnect("TParamFollower", "ParamChanged(char*)",
                           this, "OnParamChanged(char*)");
   }

   void OnParamChanged(const char* parameter)
   {
      auto pl = dynamic_cast<TEveParamList*> (reinterpret_cast<TQObject*>(gTQSender));

      printf("Change in param-list '%s', parameter '%s'.\n", pl->GetElementName(), parameter);
   }

   ClassDef(TParamFollower, 0);
};

ClassImp(TParamFollower)

void paramlist()
{
   TEveManager::Create();

   TEveParamList* x = 0;

   x = new TEveParamList("Top config");
   gEve->AddToListTree(x, 0);

   x->AddParameter(TEveParamList::FloatConfig_t("Pepe", 20, 0, 110));
   x->AddParameter(TEveParamList::IntConfig_t("Dima", 100, 0, 110));
   x->AddParameter(TEveParamList::BoolConfig_t("Chris", 1));

   x = new TEveParamList("Another config");
   gEve->AddToListTree(x, 0);

   x->AddParameter(TEveParamList::FloatConfig_t("MagneticField", 4, -4, 4));
   x->AddParameter(TEveParamList::FloatConfig_t("Temperature", 16, -20, 40));

   new TParamFollower;
}
<|endoftext|>


<commit_before>/*
 * nes.cc
 *
 *  Created on: Aug 28, 2014
 *      Author: Dale
 */

#include <exception>

#include "nes.h"
#include "mappers/nrom.h"

NES::NES(const NesParams& params)
{
    // Get just the file name from the rom path

    const std::string& romPath = params.RomPath;
    for (size_t i = romPath.length() - 1; i >= 0; --i)
    {
        if (romPath[i] == '\\' || romPath[i] == '/')
        {
            gameName = romPath.substr(i + 1, romPath.length() - i - 1);
            break;
        }
    }

    apu = new APU; // APU first since it may throw an exception
    cpu = new CPU(gameName);
    ppu = new PPU;
    cart = Cart::Create(params.RomPath, cpu);

    apu->AttachCPU(cpu);
    apu->AttachCart(cart);

    cpu->AttachPPU(ppu);
    cpu->AttachAPU(apu);
    cpu->AttachCart(cart);

    ppu->AttachCPU(cpu);
    ppu->AttachCart(cart);

    cpu->SetLogEnabled(params.CpuLogEnabled);

    ppu->SetFrameLimitEnabled(params.FrameLimitEnabled);
    ppu->SetNtscDecodingEnabled(params.NtscDecoderEnabled);

    apu->SetMuted(params.SoundMuted);
    apu->SetFiltersEnabled(params.FiltersEnabled);
}

std::string& NES::GetGameName()
{
    return gameName;
}

void NES::SetControllerOneState(uint8_t state)
{
    cpu->SetControllerOneState(state);
}

uint8_t NES::GetControllerOneState()
{
    return cpu->GetControllerOneState();
}

void NES::CpuSetLogEnabled(bool enabled)
{
    cpu->SetLogEnabled(enabled);
}

void NES::GetNameTable(int table, uint8_t* pixels)
{
    ppu->GetNameTable(table, pixels);
}

void NES::GetPatternTable(int table, int palette, uint8_t* pixels)
{
    ppu->GetPatternTable(table, palette, pixels);
}

void NES::GetPalette(int palette, uint8_t* pixels)
{
    ppu->GetPalette(palette, pixels);
}

void NES::GetPrimarySprite(int sprite, uint8_t* pixels)
{
    ppu->GetPrimaryOAM(sprite, pixels);
}

void NES::PpuSetFrameLimitEnabled(bool enabled)
{
    ppu->SetFrameLimitEnabled(enabled);
}

void NES::PpuSetNtscDecoderEnabled(bool enabled)
{
    ppu->SetNtscDecodingEnabled(enabled);
}

void NES::ApuSetMuted(bool muted)
{
    apu->SetMuted(muted);
}

void NES::ApuSetFiltersEnabled(bool enabled)
{
    apu->SetFiltersEnabled(enabled);
}

bool NES::IsStopped()
{
    return !nesThread.joinable();
}

bool NES::IsPaused()
{
    return cpu->IsPaused();
}

void NES::Start()
{
    if (!nesThread.joinable())
    {
        nesThread = std::thread(&NES::Run, this);
    }
    else
    {
        throw std::runtime_error("There is already a thread running on this NES instance.");
    }
}

void NES::Run()
{
    try
    {
        cpu->Run();
    }
    catch (std::exception& e)
    {
        if (OnError)
        {
            OnError(e.what());
        }
    }
}

void NES::Stop()
{
    cpu->Stop();

    if (nesThread.joinable())
    {
        if (std::this_thread::get_id() == nesThread.get_id())
        {
            throw std::runtime_error("NES Thread tried to stop itself!");
        }

        nesThread.join();
    }
}

void NES::Resume()
{
    cpu->Resume();
}

void NES::Pause()
{
    cpu->Pause();
}

void NES::Reset() {}

NES::~NES()
{
    delete &apu;
    delete &cpu;
    delete &ppu;
    delete &cart;
}

<commit_msg>Missed updating the delete statements in the NES classes destructor<commit_after>/*
 * nes.cc
 *
 *  Created on: Aug 28, 2014
 *      Author: Dale
 */

#include <exception>

#include "nes.h"
#include "mappers/nrom.h"

NES::NES(const NesParams& params)
{
    // Get just the file name from the rom path

    const std::string& romPath = params.RomPath;
    for (size_t i = romPath.length() - 1; i >= 0; --i)
    {
        if (romPath[i] == '\\' || romPath[i] == '/')
        {
            gameName = romPath.substr(i + 1, romPath.length() - i - 1);
            break;
        }
    }

    apu = new APU; // APU first since it may throw an exception
    cpu = new CPU(gameName);
    ppu = new PPU;
    cart = Cart::Create(params.RomPath, cpu);

    apu->AttachCPU(cpu);
    apu->AttachCart(cart);

    cpu->AttachPPU(ppu);
    cpu->AttachAPU(apu);
    cpu->AttachCart(cart);

    ppu->AttachCPU(cpu);
    ppu->AttachCart(cart);

    cpu->SetLogEnabled(params.CpuLogEnabled);

    ppu->SetFrameLimitEnabled(params.FrameLimitEnabled);
    ppu->SetNtscDecodingEnabled(params.NtscDecoderEnabled);

    apu->SetMuted(params.SoundMuted);
    apu->SetFiltersEnabled(params.FiltersEnabled);
}

std::string& NES::GetGameName()
{
    return gameName;
}

void NES::SetControllerOneState(uint8_t state)
{
    cpu->SetControllerOneState(state);
}

uint8_t NES::GetControllerOneState()
{
    return cpu->GetControllerOneState();
}

void NES::CpuSetLogEnabled(bool enabled)
{
    cpu->SetLogEnabled(enabled);
}

void NES::GetNameTable(int table, uint8_t* pixels)
{
    ppu->GetNameTable(table, pixels);
}

void NES::GetPatternTable(int table, int palette, uint8_t* pixels)
{
    ppu->GetPatternTable(table, palette, pixels);
}

void NES::GetPalette(int palette, uint8_t* pixels)
{
    ppu->GetPalette(palette, pixels);
}

void NES::GetPrimarySprite(int sprite, uint8_t* pixels)
{
    ppu->GetPrimaryOAM(sprite, pixels);
}

void NES::PpuSetFrameLimitEnabled(bool enabled)
{
    ppu->SetFrameLimitEnabled(enabled);
}

void NES::PpuSetNtscDecoderEnabled(bool enabled)
{
    ppu->SetNtscDecodingEnabled(enabled);
}

void NES::ApuSetMuted(bool muted)
{
    apu->SetMuted(muted);
}

void NES::ApuSetFiltersEnabled(bool enabled)
{
    apu->SetFiltersEnabled(enabled);
}

bool NES::IsStopped()
{
    return !nesThread.joinable();
}

bool NES::IsPaused()
{
    return cpu->IsPaused();
}

void NES::Start()
{
    if (!nesThread.joinable())
    {
        nesThread = std::thread(&NES::Run, this);
    }
    else
    {
        throw std::runtime_error("There is already a thread running on this NES instance.");
    }
}

void NES::Run()
{
    try
    {
        cpu->Run();
    }
    catch (std::exception& e)
    {
        if (OnError)
        {
            OnError(e.what());
        }
    }
}

void NES::Stop()
{
    cpu->Stop();

    if (nesThread.joinable())
    {
        if (std::this_thread::get_id() == nesThread.get_id())
        {
            throw std::runtime_error("NES Thread tried to stop itself!");
        }

        nesThread.join();
    }
}

void NES::Resume()
{
    cpu->Resume();
}

void NES::Pause()
{
    cpu->Pause();
}

void NES::Reset() {}

NES::~NES()
{
    delete apu;
    delete cpu;
    delete ppu;
    delete cart;
}

<|endoftext|>


<commit_before>#include <signal.h>
#include <functional>
#include <sstream>
#include <unordered_map>
#include "jsoncpp/json.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/onceToken.h"
#include "Util/NoticeCenter.h"
#include "Util/SqlPool.h"
#include "Common/config.h"
#include "Common/MediaSource.h"
#include "Http/HttpRequester.h"
#include "Http/HttpSession.h"
#include "Network/TcpServer.h"
#include "Player/PlayerProxy.h"

using namespace Json;
using namespace toolkit;
using namespace mediakit;

typedef map<string,variant,StrCaseCompare> ApiArgsType;

#define API_ARGS HttpSession::KeyValue &headerIn, \
                 HttpSession::KeyValue &headerOut, \
                 ApiArgsType &allArgs, \
                 Json::Value &val

#define API_REGIST(field, name, ...) \
    s_map_api.emplace("/index/"#field"/"#name,[](API_ARGS,const HttpSession::HttpResponseInvoker &invoker){ \
         static auto lam = [&](API_ARGS) __VA_ARGS__ ;  \
         lam(headerIn, headerOut, allArgs, val); \
         invoker("200 OK", headerOut, val.toStyledString()); \
     });

#define API_REGIST_INVOKER(field, name, ...) \
    s_map_api.emplace("/index/"#field"/"#name,[](API_ARGS,const HttpSession::HttpResponseInvoker &invoker) __VA_ARGS__);

//异步http api lambad定义
typedef std::function<void(API_ARGS,const HttpSession::HttpResponseInvoker &invoker)> AsyncHttpApi;
//api列表
static map<string, AsyncHttpApi> s_map_api;

namespace API {
typedef enum {
    InvalidArgsFailed = -300,
    SqlFailed = -200,
    AuthFailed = -100,
    OtherFailed = -1,
    Success = 0
} ApiErr;

#define API_FIELD "api."
const char kApiDebug[] = API_FIELD"apiDebug";
static onceToken token([]() {
    mINI::Instance()[kApiDebug] = "1";
});
}//namespace API

class ApiRetException: public std::runtime_error {
public:
    ApiRetException(const char *str = "success" ,int code = API::Success):runtime_error(str){
        _code = code;
    }
    ~ApiRetException() = default;
    int code(){ return _code; }
private:
    int _code;
};

class AuthException : public ApiRetException {
public:
    AuthException(const char *str):ApiRetException(str,API::AuthFailed){}
    ~AuthException() = default;
};

class InvalidArgs: public ApiRetException {
public:
    InvalidArgs(const char *str):ApiRetException(str,API::InvalidArgsFailed){}
    ~InvalidArgs() = default;
};

//获取HTTP请求中url参数、content参数
static ApiArgsType getAllArgs(const Parser &parser) {
    ApiArgsType allArgs;
    if(parser["Content-Type"].find("application/x-www-form-urlencoded") == 0){
        auto contentArgs = parser.parseArgs(parser.Content());
        for (auto &pr : contentArgs) {
            allArgs[pr.first] = HttpSession::urlDecode(pr.second);
        }
    }else if(parser["Content-Type"].find("application/json") == 0){
        try {
            stringstream ss(parser.Content());
            Value jsonArgs;
            ss >> jsonArgs;
            auto keys = jsonArgs.getMemberNames();
            for (auto key = keys.begin(); key != keys.end(); ++key){
                allArgs[*key] = jsonArgs[*key].asString();
            }
        }catch (std::exception &ex){
            WarnL << ex.what();
        }
    }else if(!parser["Content-Type"].empty()){
        WarnL << "invalid Content-Type:" << parser["Content-Type"];
    }

    auto &urlArgs = parser.getUrlArgs();
    for (auto &pr : urlArgs) {
        allArgs[pr.first] = HttpSession::urlDecode(pr.second);
    }
    return std::move(allArgs);
}

static inline void addHttpListener(){
    GET_CONFIG_AND_REGISTER(bool, api_debug, API::kApiDebug);
    //注册监听kBroadcastHttpRequest事件
    NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastHttpRequest, [](BroadcastHttpRequestArgs) {
        auto it = s_map_api.find(parser.Url());
        if (it == s_map_api.end()) {
            consumed = false;
            return;
        }
        //该api已被消费
        consumed = true;
        AsyncHttpApi api = it->second;
        //异步执行该api，防止阻塞NoticeCenter
        EventPollerPool::Instance().getExecutor()->async([api, parser, invoker]() {
            //执行API
            Json::Value val;
            val["code"] = API::Success;
            HttpSession::KeyValue &headerIn = parser.getValues();
            HttpSession::KeyValue headerOut;
            auto allArgs = getAllArgs(parser);
            headerOut["Content-Type"] = "application/json; charset=utf-8";
            if(api_debug){
                auto newInvoker = [invoker,parser,allArgs](const string &codeOut,
                                                           const HttpSession::KeyValue &headerOut,
                                                           const string &contentOut){
                    stringstream ss;
                    for(auto &pr : allArgs ){
                        ss << pr.first << " : " << pr.second << "\r\n";
                    }

                    DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
                           << "# content:\r\n" << parser.Content() << "\r\n"
                           << "# args:\r\n" << ss.str()
                           << "# response:\r\n"
                           << contentOut << "\r\n";

                    invoker(codeOut,headerOut,contentOut);
                };
                ((HttpSession::HttpResponseInvoker &)invoker) = newInvoker;
            }

            try {
                api(headerIn, headerOut, allArgs, val, invoker);
            }  catch(ApiRetException &ex){
                val["code"] = ex.code();
                val["msg"] = ex.what();
                invoker("200 OK", headerOut, val.toStyledString());
            } catch(SqlException &ex){
                val["code"] = API::SqlFailed;
                val["msg"] = StrPrinter << "操作数据库失败:" << ex.what() << ":" << ex.getSql();
                WarnL << ex.what() << ":" << ex.getSql();
                invoker("200 OK", headerOut, val.toStyledString());
            } catch (std::exception &ex) {
                val["code"] = API::OtherFailed;
                val["msg"] = ex.what();
                invoker("200 OK", headerOut, val.toStyledString());
            }
        });
    });
}

template <typename Args,typename First>
bool checArgs(Args &&args,First &&first){
    return !args[first].empty();
}

template <typename Args,typename First,typename ...KeyTypes>
bool checArgs(Args &&args,First &&first,KeyTypes && ...keys){
    return !args[first].empty() && checArgs(args,keys...);
}

#define CHECK_ARGS(...)  \
    if(!checArgs(allArgs,##__VA_ARGS__)){ \
        throw InvalidArgs("缺少必要参数:" #__VA_ARGS__); \
    }

//安装api接口
void installWebApi() {
    addHttpListener();

    /**
     * 获取线程负载
     */
    API_REGIST_INVOKER(api, getThreadsLoad, {
        EventPollerPool::Instance().getExecutorDelay([invoker, headerOut](const vector<int> &vecDelay) {
            Value val;
            auto vec = EventPollerPool::Instance().getExecutorLoad();
            int i = 0;
            for (auto load : vec) {
                Value obj(objectValue);
                obj["load"] = load;
                obj["delay"] = vecDelay[i++];
                val["data"].append(obj);
            }
            invoker("200 OK", headerOut, val.toStyledString());
        });
    });

    /**
     * 获取服务器配置
     */
    API_REGIST(api, getServerConfig, {
        Value obj;
        for (auto &pr : mINI::Instance()) {
            obj[pr.first] = (string &) pr.second;
        }
        val["data"].append(obj);
    });

    /**
     * 设置服务器配置
     */
    API_REGIST(api, setServerConfig, {
        auto &ini = mINI::Instance();
        int changed = 0;
        for (auto &pr : allArgs) {
            if (ini.find(pr.first) == ini.end()) {
                //没有这个key
                continue;
            }
            if (ini[pr.first] == pr.second) {
                continue;
            }
            ini[pr.first] = pr.second;
            //替换成功
            ++changed;
        }
        if (changed > 0) {
            NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
            ini.dumpFile();
        }
        val["changed"] = changed;
    });

    /**
     * 获取服务器api列表
     */
    API_REGIST(api,getApiList,{
        for(auto &pr : s_map_api){
            val["data"].append(pr.first);
        }
    });

    /**
     * 重启服务器
     */
    API_REGIST(api,restartServer,{
        EventPollerPool::Instance().getPoller()->doDelayTask(1000,[](){
            //尝试正常退出
            ::kill(getpid(), SIGINT);

            //3秒后强制退出
            EventPollerPool::Instance().getPoller()->doDelayTask(3000,[](){
                exit(0);
                return 0;
            });

            return 0;
        });
        val["msg"] = "服务器将在一秒后自动重启";
    });

    API_REGIST(api,getMediaList,{
        //获取所有MediaSource列表
        val["code"] = 0;
        val["msg"] = "success";
        MediaSource::for_each_media([&](const string &schema,
                                        const string &vhost,
                                        const string &app,
                                        const string &stream,
                                        const MediaSource::Ptr &media){
            if(!allArgs["schema"].empty() && allArgs["schema"] != schema){
                return;
            }
            if(!allArgs["vhost"].empty() && allArgs["vhost"] != vhost){
                return;
            }
            if(!allArgs["app"].empty() && allArgs["app"] != app){
                return;
            }
            Value item;
            item["schema"] = schema;
            item["vhost"] = vhost;
            item["app"] = app;
            item["stream"] = stream;
            val["data"].append(item);
        });
    });

    API_REGIST(api,kick_pusher,{
        CHECK_ARGS("schema","vhost","app","stream");
        //踢掉推流器
        auto src = MediaSource::find(allArgs["schema"],
                                     allArgs["vhost"],
                                     allArgs["app"],
                                     allArgs["stream"]);
        if(src){
            bool flag = src->close();
            val["code"] = flag ? 0 : -1;
            val["msg"] = flag ? "success" : "kick failed";
        }else{
            val["code"] = -2;
            val["msg"] = "can not find the pusher";
        }
    });

    API_REGIST(api,kick_session,{
        CHECK_ARGS("id");
        //踢掉tcp会话
        auto id = allArgs["id"];
        if(id.empty()){
            val["code"] = -1;
            val["msg"] = "illegal parameter:id";
            return;
        }
        auto session = SessionMap::Instance().get(id);
        if(!session){
            val["code"] = -2;
            val["msg"] = "can not find the target";
            return;
        }
        session->safeShutdown();
        val["code"] = 0;
        val["msg"] = "success";
    });

    static unordered_map<uint64_t ,PlayerProxy::Ptr> s_proxyMap;
    static recursive_mutex s_proxyMapMtx;
    API_REGIST(api,addStreamProxy,{
        CHECK_ARGS("vhost","app","stream","url");
        //添加拉流代理
        PlayerProxy::Ptr player(new PlayerProxy(
                allArgs["vhost"],
                allArgs["app"],
                allArgs["stream"],
                allArgs["enable_hls"],
                allArgs["enable_mp4"]
        ));
        //指定RTP over TCP(播放rtsp时有效)
        (*player)[kRtpType] = allArgs["rtp_type"].as<int>();
        //开始播放，如果播放失败或者播放中止，将会自动重试若干次，重试次数在配置文件中配置，默认一直重试
        player->play(allArgs["url"]);

        val["data"]["id"] = player.get();
        lock_guard<recursive_mutex> lck(s_proxyMapMtx);
        s_proxyMap[(uint64_t)player.get()] = player;
    });

    API_REGIST(api,delStreamProxy,{
        CHECK_ARGS("id");
        lock_guard<recursive_mutex> lck(s_proxyMapMtx);
        val["data"]["flag"] = s_proxyMap.erase(allArgs["id"].as<uint64_t>()) == 1;
    });

    ////////////以下是注册的Hook API////////////
    API_REGIST(hook,on_publish,{
        //开始推流事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_play,{
        //开始播放事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_flow_report,{
        //流量统计hook api
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_rtsp_realm,{
        //rtsp是否需要鉴权
        val["code"] = 0;
        val["realm"] = "zlmediakit_reaml";
    });

    API_REGIST(hook,on_rtsp_auth,{
        //rtsp鉴权密码，密码等于用户名
        //rtsp可以有双重鉴权！后面还会触发on_play事件
        CHECK_ARGS("user_name");
        val["code"] = 0;
        val["encrypted"] = false;
        val["passwd"] = allArgs["user_name"].data();
    });

    API_REGIST(hook,on_stream_changed,{
        //媒体注册或反注册事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_stream_not_found,{
        //媒体未找到事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_record_mp4,{
        //录制mp4分片完毕事件
        val["code"] = 0;
        val["msg"] = "success";
    });

}<commit_msg>完善checkArgs函数<commit_after>#include <signal.h>
#include <functional>
#include <sstream>
#include <unordered_map>
#include "jsoncpp/json.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/onceToken.h"
#include "Util/NoticeCenter.h"
#include "Util/SqlPool.h"
#include "Common/config.h"
#include "Common/MediaSource.h"
#include "Http/HttpRequester.h"
#include "Http/HttpSession.h"
#include "Network/TcpServer.h"
#include "Player/PlayerProxy.h"

using namespace Json;
using namespace toolkit;
using namespace mediakit;

typedef map<string,variant,StrCaseCompare> ApiArgsType;

#define API_ARGS HttpSession::KeyValue &headerIn, \
                 HttpSession::KeyValue &headerOut, \
                 ApiArgsType &allArgs, \
                 Json::Value &val

#define API_REGIST(field, name, ...) \
    s_map_api.emplace("/index/"#field"/"#name,[](API_ARGS,const HttpSession::HttpResponseInvoker &invoker){ \
         static auto lam = [&](API_ARGS) __VA_ARGS__ ;  \
         lam(headerIn, headerOut, allArgs, val); \
         invoker("200 OK", headerOut, val.toStyledString()); \
     });

#define API_REGIST_INVOKER(field, name, ...) \
    s_map_api.emplace("/index/"#field"/"#name,[](API_ARGS,const HttpSession::HttpResponseInvoker &invoker) __VA_ARGS__);

//异步http api lambad定义
typedef std::function<void(API_ARGS,const HttpSession::HttpResponseInvoker &invoker)> AsyncHttpApi;
//api列表
static map<string, AsyncHttpApi> s_map_api;

namespace API {
typedef enum {
    InvalidArgsFailed = -300,
    SqlFailed = -200,
    AuthFailed = -100,
    OtherFailed = -1,
    Success = 0
} ApiErr;

#define API_FIELD "api."
const char kApiDebug[] = API_FIELD"apiDebug";
static onceToken token([]() {
    mINI::Instance()[kApiDebug] = "1";
});
}//namespace API

class ApiRetException: public std::runtime_error {
public:
    ApiRetException(const char *str = "success" ,int code = API::Success):runtime_error(str){
        _code = code;
    }
    ~ApiRetException() = default;
    int code(){ return _code; }
private:
    int _code;
};

class AuthException : public ApiRetException {
public:
    AuthException(const char *str):ApiRetException(str,API::AuthFailed){}
    ~AuthException() = default;
};

class InvalidArgs: public ApiRetException {
public:
    InvalidArgs(const char *str):ApiRetException(str,API::InvalidArgsFailed){}
    ~InvalidArgs() = default;
};

//获取HTTP请求中url参数、content参数
static ApiArgsType getAllArgs(const Parser &parser) {
    ApiArgsType allArgs;
    if(parser["Content-Type"].find("application/x-www-form-urlencoded") == 0){
        auto contentArgs = parser.parseArgs(parser.Content());
        for (auto &pr : contentArgs) {
            allArgs[pr.first] = HttpSession::urlDecode(pr.second);
        }
    }else if(parser["Content-Type"].find("application/json") == 0){
        try {
            stringstream ss(parser.Content());
            Value jsonArgs;
            ss >> jsonArgs;
            auto keys = jsonArgs.getMemberNames();
            for (auto key = keys.begin(); key != keys.end(); ++key){
                allArgs[*key] = jsonArgs[*key].asString();
            }
        }catch (std::exception &ex){
            WarnL << ex.what();
        }
    }else if(!parser["Content-Type"].empty()){
        WarnL << "invalid Content-Type:" << parser["Content-Type"];
    }

    auto &urlArgs = parser.getUrlArgs();
    for (auto &pr : urlArgs) {
        allArgs[pr.first] = HttpSession::urlDecode(pr.second);
    }
    return std::move(allArgs);
}

static inline void addHttpListener(){
    GET_CONFIG_AND_REGISTER(bool, api_debug, API::kApiDebug);
    //注册监听kBroadcastHttpRequest事件
    NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastHttpRequest, [](BroadcastHttpRequestArgs) {
        auto it = s_map_api.find(parser.Url());
        if (it == s_map_api.end()) {
            consumed = false;
            return;
        }
        //该api已被消费
        consumed = true;
        AsyncHttpApi api = it->second;
        //异步执行该api，防止阻塞NoticeCenter
        EventPollerPool::Instance().getExecutor()->async([api, parser, invoker]() {
            //执行API
            Json::Value val;
            val["code"] = API::Success;
            HttpSession::KeyValue &headerIn = parser.getValues();
            HttpSession::KeyValue headerOut;
            auto allArgs = getAllArgs(parser);
            headerOut["Content-Type"] = "application/json; charset=utf-8";
            if(api_debug){
                auto newInvoker = [invoker,parser,allArgs](const string &codeOut,
                                                           const HttpSession::KeyValue &headerOut,
                                                           const string &contentOut){
                    stringstream ss;
                    for(auto &pr : allArgs ){
                        ss << pr.first << " : " << pr.second << "\r\n";
                    }

                    DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
                           << "# content:\r\n" << parser.Content() << "\r\n"
                           << "# args:\r\n" << ss.str()
                           << "# response:\r\n"
                           << contentOut << "\r\n";

                    invoker(codeOut,headerOut,contentOut);
                };
                ((HttpSession::HttpResponseInvoker &)invoker) = newInvoker;
            }

            try {
                api(headerIn, headerOut, allArgs, val, invoker);
            }  catch(ApiRetException &ex){
                val["code"] = ex.code();
                val["msg"] = ex.what();
                invoker("200 OK", headerOut, val.toStyledString());
            } catch(SqlException &ex){
                val["code"] = API::SqlFailed;
                val["msg"] = StrPrinter << "操作数据库失败:" << ex.what() << ":" << ex.getSql();
                WarnL << ex.what() << ":" << ex.getSql();
                invoker("200 OK", headerOut, val.toStyledString());
            } catch (std::exception &ex) {
                val["code"] = API::OtherFailed;
                val["msg"] = ex.what();
                invoker("200 OK", headerOut, val.toStyledString());
            }
        });
    });
}

template <typename Args,typename First>
bool checkArgs(Args &&args,First &&first){
    return !args[first].empty();
}

template <typename Args,typename First,typename ...KeyTypes>
bool checkArgs(Args &&args,First &&first,KeyTypes && ...keys){
    return !args[first].empty() && checkArgs(std::forward<Args>(args),std::forward<KeyTypes>(keys)...);
}

#define CHECK_ARGS(...)  \
    if(!checkArgs(allArgs,##__VA_ARGS__)){ \
        throw InvalidArgs("缺少必要参数:" #__VA_ARGS__); \
    }

//安装api接口
void installWebApi() {
    addHttpListener();

    /**
     * 获取线程负载
     */
    API_REGIST_INVOKER(api, getThreadsLoad, {
        EventPollerPool::Instance().getExecutorDelay([invoker, headerOut](const vector<int> &vecDelay) {
            Value val;
            auto vec = EventPollerPool::Instance().getExecutorLoad();
            int i = 0;
            for (auto load : vec) {
                Value obj(objectValue);
                obj["load"] = load;
                obj["delay"] = vecDelay[i++];
                val["data"].append(obj);
            }
            invoker("200 OK", headerOut, val.toStyledString());
        });
    });

    /**
     * 获取服务器配置
     */
    API_REGIST(api, getServerConfig, {
        Value obj;
        for (auto &pr : mINI::Instance()) {
            obj[pr.first] = (string &) pr.second;
        }
        val["data"].append(obj);
    });

    /**
     * 设置服务器配置
     */
    API_REGIST(api, setServerConfig, {
        auto &ini = mINI::Instance();
        int changed = 0;
        for (auto &pr : allArgs) {
            if (ini.find(pr.first) == ini.end()) {
                //没有这个key
                continue;
            }
            if (ini[pr.first] == pr.second) {
                continue;
            }
            ini[pr.first] = pr.second;
            //替换成功
            ++changed;
        }
        if (changed > 0) {
            NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
            ini.dumpFile();
        }
        val["changed"] = changed;
    });

    /**
     * 获取服务器api列表
     */
    API_REGIST(api,getApiList,{
        for(auto &pr : s_map_api){
            val["data"].append(pr.first);
        }
    });

    /**
     * 重启服务器
     */
    API_REGIST(api,restartServer,{
        EventPollerPool::Instance().getPoller()->doDelayTask(1000,[](){
            //尝试正常退出
            ::kill(getpid(), SIGINT);

            //3秒后强制退出
            EventPollerPool::Instance().getPoller()->doDelayTask(3000,[](){
                exit(0);
                return 0;
            });

            return 0;
        });
        val["msg"] = "服务器将在一秒后自动重启";
    });

    API_REGIST(api,getMediaList,{
        //获取所有MediaSource列表
        val["code"] = 0;
        val["msg"] = "success";
        MediaSource::for_each_media([&](const string &schema,
                                        const string &vhost,
                                        const string &app,
                                        const string &stream,
                                        const MediaSource::Ptr &media){
            if(!allArgs["schema"].empty() && allArgs["schema"] != schema){
                return;
            }
            if(!allArgs["vhost"].empty() && allArgs["vhost"] != vhost){
                return;
            }
            if(!allArgs["app"].empty() && allArgs["app"] != app){
                return;
            }
            Value item;
            item["schema"] = schema;
            item["vhost"] = vhost;
            item["app"] = app;
            item["stream"] = stream;
            val["data"].append(item);
        });
    });

    API_REGIST(api,kick_pusher,{
        CHECK_ARGS("schema","vhost","app","stream");
        //踢掉推流器
        auto src = MediaSource::find(allArgs["schema"],
                                     allArgs["vhost"],
                                     allArgs["app"],
                                     allArgs["stream"]);
        if(src){
            bool flag = src->close();
            val["code"] = flag ? 0 : -1;
            val["msg"] = flag ? "success" : "kick failed";
        }else{
            val["code"] = -2;
            val["msg"] = "can not find the pusher";
        }
    });

    API_REGIST(api,kick_session,{
        CHECK_ARGS("id");
        //踢掉tcp会话
        auto id = allArgs["id"];
        if(id.empty()){
            val["code"] = -1;
            val["msg"] = "illegal parameter:id";
            return;
        }
        auto session = SessionMap::Instance().get(id);
        if(!session){
            val["code"] = -2;
            val["msg"] = "can not find the target";
            return;
        }
        session->safeShutdown();
        val["code"] = 0;
        val["msg"] = "success";
    });

    static unordered_map<uint64_t ,PlayerProxy::Ptr> s_proxyMap;
    static recursive_mutex s_proxyMapMtx;
    API_REGIST(api,addStreamProxy,{
        CHECK_ARGS("vhost","app","stream","url");
        //添加拉流代理
        PlayerProxy::Ptr player(new PlayerProxy(
                allArgs["vhost"],
                allArgs["app"],
                allArgs["stream"],
                allArgs["enable_hls"],
                allArgs["enable_mp4"]
        ));
        //指定RTP over TCP(播放rtsp时有效)
        (*player)[kRtpType] = allArgs["rtp_type"].as<int>();
        //开始播放，如果播放失败或者播放中止，将会自动重试若干次，重试次数在配置文件中配置，默认一直重试
        player->play(allArgs["url"]);

        val["data"]["id"] = player.get();
        lock_guard<recursive_mutex> lck(s_proxyMapMtx);
        s_proxyMap[(uint64_t)player.get()] = player;
    });

    API_REGIST(api,delStreamProxy,{
        CHECK_ARGS("id");
        lock_guard<recursive_mutex> lck(s_proxyMapMtx);
        val["data"]["flag"] = s_proxyMap.erase(allArgs["id"].as<uint64_t>()) == 1;
    });

    ////////////以下是注册的Hook API////////////
    API_REGIST(hook,on_publish,{
        //开始推流事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_play,{
        //开始播放事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_flow_report,{
        //流量统计hook api
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_rtsp_realm,{
        //rtsp是否需要鉴权
        val["code"] = 0;
        val["realm"] = "zlmediakit_reaml";
    });

    API_REGIST(hook,on_rtsp_auth,{
        //rtsp鉴权密码，密码等于用户名
        //rtsp可以有双重鉴权！后面还会触发on_play事件
        CHECK_ARGS("user_name");
        val["code"] = 0;
        val["encrypted"] = false;
        val["passwd"] = allArgs["user_name"].data();
    });

    API_REGIST(hook,on_stream_changed,{
        //媒体注册或反注册事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_stream_not_found,{
        //媒体未找到事件
        val["code"] = 0;
        val["msg"] = "success";
    });

    API_REGIST(hook,on_record_mp4,{
        //录制mp4分片完毕事件
        val["code"] = 0;
        val["msg"] = "success";
    });

}<|endoftext|>


<commit_before>#include <v8.h>
#include <string>

#ifdef FASTCGI
#  include <fcgi_stdio.h>
#endif

#include "js_macros.h"
#include "js_common.h"
#include "js_app.h"
#include "js_system.h"
#include "js_path.h"

#ifndef HAVE_SLEEP
#	include <windows.h>
#	define sleep(num) { Sleep(num * 1000); }
#endif

namespace {

/**
 * Read characters from stdin
 * @param {int} count How many; 0 == all
 * @param {bool} [arr=false] Return as array of bytes?
 */
JS_METHOD(_stdin) {
	v8cgi_App * app = APP_PTR;

	size_t count = 0;
	if (args.Length() && args[0]->IsNumber()) {
		count = args[0]->IntegerValue();
	}

	std::string data;
	size_t size = 0;

   if (count == 0) { /* all */
		size_t tmp;
		char * buf = new char[1024];
		do {
			tmp = app->reader(buf, sizeof(buf));
			size += tmp;
			data.insert(data.length(), buf, tmp);
		} while (tmp == sizeof(buf));
		delete[] buf;
	} else {
		char * tmp = new char[count];
		size = app->reader(tmp, count);
		data.insert(0, tmp, size);
		delete[] tmp;
	}

	if (args.Length() > 1 && args[1]->IsTrue()) {
		return JS_CHARARRAY((char *) data.data(), size);
	} else {
		return JS_STR(data.data(), size);
	}
}

/**
 * Dump data to stdout
 * @param {string|int[]} String or array of bytes
 */
JS_METHOD(_stdout) {
	v8cgi_App * app = APP_PTR;
	if (args[0]->IsArray()) {
		v8::Handle<v8::Array> arr = v8::Handle<v8::Array>::Cast(args[0]);
		uint32_t len = arr->Length();
		std::string data;
		for (unsigned int i=0;i<len;i++) {
			data += (char) arr->Get(JS_INT(i))->Int32Value();
		}
		app->writer((char *) data.data(), len);
	} else {
		v8::String::Utf8Value str(args[0]);
		app->writer(*str, str.length());
	}
	return v8::Undefined();
}

JS_METHOD(_stderr) {
	v8cgi_App * app = APP_PTR;
	v8::String::Utf8Value str(args[0]);
	v8::String::Utf8Value f(args[1]);
	int line = args[2]->Int32Value();
	app->error(*str, *f, line);
	return v8::Undefined();
}

JS_METHOD(_getcwd) {
	return JS_STR(path_getcwd().c_str());
}

/**
 * Sleep for a given number of seconds
 */
JS_METHOD(_sleep) {
	int num = args[0]->Int32Value();
	sleep(num);
	return v8::Undefined();
}

/**
 * FIXME: How to do this on win32?
JS_METHOD(_usleep) {
	v8::HandleScope handle_scope;
	int num = args[0]->Int32Value();
	usleep(num);
	return v8::Undefined();
}
*/

}

void setup_system(v8::Handle<v8::Object> global, char ** envp, std::string mainfile, std::vector<std::string> args) {
	v8::HandleScope handle_scope;
	v8::Handle<v8::ObjectTemplate> systemt = v8::ObjectTemplate::New();
	v8::Handle<v8::Object> system = systemt->NewInstance();
	v8::Handle<v8::Object> env = v8::Object::New();
	global->Set(JS_STR("system"), system);

	/**
	 * Create system.args
	 */
	v8::Handle<v8::Array> arr = v8::Array::New();
	arr->Set(JS_INT(0), JS_STR(mainfile.c_str()));
	for (size_t i = 0; i < args.size(); ++i) {
		arr->Set(JS_INT(i+1), JS_STR(args.at(i).c_str()));
	}
	system->Set(JS_STR("args"), arr);

	system->Set(JS_STR("stdin"), v8::FunctionTemplate::New(_stdin)->GetFunction());
	system->Set(JS_STR("stdout"), v8::FunctionTemplate::New(_stdout)->GetFunction());
	system->Set(JS_STR("stderr"), v8::FunctionTemplate::New(_stderr)->GetFunction());
	system->Set(JS_STR("getcwd"), v8::FunctionTemplate::New(_getcwd)->GetFunction());
	system->Set(JS_STR("sleep"), v8::FunctionTemplate::New(_sleep)->GetFunction());
/*	system->Set(JS_STR("usleep"), v8::FunctionTemplate::New(_usleep)->GetFunction()); */
	system->Set(JS_STR("env"), env);

	std::string name, value;
	bool done;
	int i,j;
	char ch;

	/* extract environment variables and create JS object */
	for (i = 0; envp[i] != NULL; i++) {
		done = false;
		name = "";
		value = "";
		for (j = 0; envp[i][j] != '\0'; j++) {
			ch = envp[i][j];
			if (!done) {
				if (ch == '=') {
					done = true;
				} else {
					name += ch;
				}
			} else {
				value += ch;
			}
		}
		env->Set(JS_STR(name.c_str()), JS_STR(value.c_str()));
	}
}
<commit_msg>#46 usleep<commit_after>#include <v8.h>
#include <string>

#ifdef FASTCGI
#  include <fcgi_stdio.h>
#endif

#include "js_macros.h"
#include "js_common.h"
#include "js_app.h"
#include "js_system.h"
#include "js_path.h"

#ifndef HAVE_SLEEP
#	include <windows.h>
#	define sleep(num) { Sleep(num * 1000); }
#endif

namespace {

/**
 * Read characters from stdin
 * @param {int} count How many; 0 == all
 * @param {bool} [arr=false] Return as array of bytes?
 */
JS_METHOD(_stdin) {
	v8cgi_App * app = APP_PTR;

	size_t count = 0;
	if (args.Length() && args[0]->IsNumber()) {
		count = args[0]->IntegerValue();
	}

	std::string data;
	size_t size = 0;

   if (count == 0) { /* all */
		size_t tmp;
		char * buf = new char[1024];
		do {
			tmp = app->reader(buf, sizeof(buf));
			size += tmp;
			data.insert(data.length(), buf, tmp);
		} while (tmp == sizeof(buf));
		delete[] buf;
	} else {
		char * tmp = new char[count];
		size = app->reader(tmp, count);
		data.insert(0, tmp, size);
		delete[] tmp;
	}

	if (args.Length() > 1 && args[1]->IsTrue()) {
		return JS_CHARARRAY((char *) data.data(), size);
	} else {
		return JS_STR(data.data(), size);
	}
}

/**
 * Dump data to stdout
 * @param {string|int[]} String or array of bytes
 */
JS_METHOD(_stdout) {
	v8cgi_App * app = APP_PTR;
	if (args[0]->IsArray()) {
		v8::Handle<v8::Array> arr = v8::Handle<v8::Array>::Cast(args[0]);
		uint32_t len = arr->Length();
		std::string data;
		for (unsigned int i=0;i<len;i++) {
			data += (char) arr->Get(JS_INT(i))->Int32Value();
		}
		app->writer((char *) data.data(), len);
	} else {
		v8::String::Utf8Value str(args[0]);
		app->writer(*str, str.length());
	}
	return v8::Undefined();
}

JS_METHOD(_stderr) {
	v8cgi_App * app = APP_PTR;
	v8::String::Utf8Value str(args[0]);
	v8::String::Utf8Value f(args[1]);
	int line = args[2]->Int32Value();
	app->error(*str, *f, line);
	return v8::Undefined();
}

JS_METHOD(_getcwd) {
	return JS_STR(path_getcwd().c_str());
}

/**
 * Sleep for a given number of seconds
 */
JS_METHOD(_sleep) {
	int num = args[0]->Int32Value();
	sleep(num);
	return v8::Undefined();
}

/**
 * Sleep for a given number of microseconds
 */
JS_METHOD(_usleep) {
	v8::HandleScope handle_scope;
	int num = args[0]->Int32Value();
	usleep(num);
	return v8::Undefined();
}

}

void setup_system(v8::Handle<v8::Object> global, char ** envp, std::string mainfile, std::vector<std::string> args) {
	v8::HandleScope handle_scope;
	v8::Handle<v8::ObjectTemplate> systemt = v8::ObjectTemplate::New();
	v8::Handle<v8::Object> system = systemt->NewInstance();
	v8::Handle<v8::Object> env = v8::Object::New();
	global->Set(JS_STR("system"), system);

	/**
	 * Create system.args
	 */
	v8::Handle<v8::Array> arr = v8::Array::New();
	arr->Set(JS_INT(0), JS_STR(mainfile.c_str()));
	for (size_t i = 0; i < args.size(); ++i) {
		arr->Set(JS_INT(i+1), JS_STR(args.at(i).c_str()));
	}
	system->Set(JS_STR("args"), arr);

	system->Set(JS_STR("stdin"), v8::FunctionTemplate::New(_stdin)->GetFunction());
	system->Set(JS_STR("stdout"), v8::FunctionTemplate::New(_stdout)->GetFunction());
	system->Set(JS_STR("stderr"), v8::FunctionTemplate::New(_stderr)->GetFunction());
	system->Set(JS_STR("getcwd"), v8::FunctionTemplate::New(_getcwd)->GetFunction());
	system->Set(JS_STR("sleep"), v8::FunctionTemplate::New(_sleep)->GetFunction());
	system->Set(JS_STR("usleep"), v8::FunctionTemplate::New(_usleep)->GetFunction());
	system->Set(JS_STR("env"), env);

	std::string name, value;
	bool done;
	int i,j;
	char ch;

	/* extract environment variables and create JS object */
	for (i = 0; envp[i] != NULL; i++) {
		done = false;
		name = "";
		value = "";
		for (j = 0; envp[i][j] != '\0'; j++) {
			ch = envp[i][j];
			if (!done) {
				if (ch == '=') {
					done = true;
				} else {
					name += ch;
				}
			} else {
				value += ch;
			}
		}
		env->Set(JS_STR(name.c_str()), JS_STR(value.c_str()));
	}
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016,
Dan Bethell, Johannes Saam, Vahan Sosoyan, Brian Scherbinski.
All rights reserved. See COPYING.txt for more details.
*/

#include "FrameBuffer.h"
#include "boost/format.hpp"

using namespace aton;

const std::string chStr::RGBA = "RGBA",
                  chStr::rgb = "rgb",
                  chStr::depth = "depth",
                  chStr::Z = "Z",
                  chStr::N = "N",
                  chStr::P = "P",
                  chStr::_red = ".red",
                  chStr::_green = ".green",
                  chStr::_blue = ".blue",
                  chStr::_X = ".X",
                  chStr::_Y = ".Y",
                  chStr::_Z = ".Z";

// Lightweight color pixel class
RenderColor::RenderColor() { _val[0] = _val[1] = _val[2] = 0.0f; }

float& RenderColor::operator[](int i) { return _val[i]; }
const float& RenderColor::operator[](int i) const { return _val[i]; }

// RenderBuffer class
RenderBuffer::RenderBuffer(const unsigned int& width,
                           const unsigned int& height,
                           const int& spp)
{
    size_t size = width * height;

    switch (spp)
    {
        case 1: // Float channels
            _float_data.resize(size);
            break;
        case 3: // Color Channels
            _color_data.resize(size);
            break;
        case 4: // Color + Alpha channels
            _color_data.resize(size);
            _float_data.resize(size);
            break;
    }
}

// FrameBuffer class
FrameBuffer::FrameBuffer(const double& currentFrame,
                         const int& w,
                         const int& h): _frame(currentFrame),
                                        _width(w),
                                        _height(h),
                                        _progress(0),
                                        _time(0),
                                        _ram(0),
                                        _pram(0),
                                        _ready(false) {}

// Add new buffer
void FrameBuffer::addBuffer(const char* aov,
                            const int& spp)
{
    RenderBuffer buffer(_width, _height, spp);

    _buffers.push_back(buffer);
    _aovs.push_back(aov);
}

// Get writable buffer object
void FrameBuffer::setBufferPix(const int& b,
                               const unsigned int& x,
                               const unsigned int& y,
                               const int& spp,
                               const int& c,
                               const float& pix)
{
    RenderBuffer& rb = _buffers[b];
    unsigned int index = (_width * y) + x;
    if (c < 3 && spp != 1)
        rb._color_data[index][c] = pix;
    else
        rb._float_data[index] = pix;
}

// Get read only buffer object
const float& FrameBuffer::getBufferPix(const int& b,
                                       const unsigned int& x,
                                       const unsigned int& y,
                                       const int& c) const
{
    const RenderBuffer& rb = _buffers[b];
    unsigned int index = (_width * y) + x;
    if (c < 3 && !rb._color_data.empty())
        return rb._color_data[index][c];
    else
        return rb._float_data[index];
}

// Get the current buffer index
int FrameBuffer::getBufferIndex(const Channel& z)
{
    int b_index = 0;
    if (_aovs.size() > 1)
    {
        using namespace chStr;
        std::string layer = getLayerName(z);

        std::vector<std::string>::iterator it;
        for(it = _aovs.begin(); it != _aovs.end(); ++it)
        {
            if (*it == layer)
            {
                b_index = static_cast<int>(it - _aovs.begin());
                break;
            }
            else if (*it == Z && layer == depth)
            {
                b_index = static_cast<int>(it - _aovs.begin());
                break;
            }
        }

    }
    return b_index;
}

// Get the current buffer index
int FrameBuffer::getBufferIndex(const char* aovName)
{
    int b_index = 0;
    if (_aovs.size() > 1)
    {
        std::vector<std::string>::iterator it;
        for(it = _aovs.begin(); it != _aovs.end(); ++it)
        {
            if (*it == aovName)
            {
                b_index = static_cast<int>(it - _aovs.begin());
                break;
            }
        }
    }
    return b_index;
}

// Get N buffer/aov name name
const char* FrameBuffer::getBufferName(const int& index)
{
    const char* aovName = "";

    if(!_aovs.empty())
        try
        {
            aovName = _aovs.at(index).c_str();
        }
        catch (...){}

    return aovName;
}

// Get last buffer/aov name
bool FrameBuffer::isFirstBufferName(const char* aovName)
{
    return strcmp(_aovs.front().c_str(), aovName) == 0;;
}

// Check if Frame has been changed
bool FrameBuffer::isFrameChanged(const double& frame)
{
    return frame != _frame;
}

// Check if Aovs has been changed
bool FrameBuffer::isAovsChanged(const std::vector<std::string>& aovs)
{
    return (aovs != _aovs);
}

// Check if Resolution has been changed
bool FrameBuffer::isResolutionChanged(const unsigned int& width,
                                      const unsigned int& height)
{
    return (width != _width && height != _height);
}

// Clear buffers and aovs
void FrameBuffer::clearAll()
{
    _buffers = std::vector<RenderBuffer>();
    _aovs = std::vector<std::string>();
}

// Check if the given buffer/aov name name is exist
bool FrameBuffer::isBufferExist(const char* aovName)
{
    return std::find(_aovs.begin(),
                     _aovs.end(), aovName) != _aovs.end();
}

// Set width of the buffer
void FrameBuffer::setWidth(const int& w) { _width = w; }

// Set height of the buffer
void FrameBuffer::setHeight(const int& h) { _height = h; }

// Get width of the buffer
const int& FrameBuffer::getWidth() { return _width; }

// Get height of the buffer
const int& FrameBuffer::getHeight() { return _height; }

// Get size of the buffers aka AOVs count
size_t FrameBuffer::size() { return _aovs.size(); }

// Resize the buffers
void FrameBuffer::resize(const size_t& s)
{
    _buffers.resize(s);
    _aovs.resize(s);
}

// Set status parameters
void FrameBuffer::setProgress(const long long& progress)
{
    _progress = progress > 100 ? 100 : progress;
}

void FrameBuffer::setRAM(const long long& ram)
{
    int ramGb = static_cast<int>(ram / 1048576);
    _ram = ramGb;
    _pram = ramGb > _pram ? ramGb : _pram;

}
void FrameBuffer::setTime(const int& time,
                          const int& dtime)
{
    _time = dtime > time ? time : time - dtime;
}

// Get status parameters
const long long& FrameBuffer::getProgress() { return _progress; }
const long long& FrameBuffer::getRAM() { return _ram; }
const long long& FrameBuffer::getPRAM() { return _pram; }
const int& FrameBuffer::getTime() { return _time; }

// Set Arnold core version
void FrameBuffer::setArnoldVersion(const int& version)
{
    // Construct a string from the version number passed
    int archV = (version % 10000000) / 1000000;
    int majorV = (version % 1000000) / 10000;
    int minorV = (version % 10000) / 100;
    int fixV = version % 100;

    std::stringstream stream;
    stream << archV << "." << majorV << "." << minorV << "." << fixV;
    _version = stream.str();
}

// Get Arnold core version
const char* FrameBuffer::getArnoldVersion() { return _version.c_str(); }

// Set the frame number of this framebuffer
void FrameBuffer::setFrame(const double& frame) { _frame = frame; }

// Get the frame number of this framebuffer
const double& FrameBuffer::getFrame() { return _frame; }

// Check if this framebuffer is empty
bool FrameBuffer::empty() { return (_buffers.empty() && _aovs.empty()) ; }

// To keep False while writing the buffer
void FrameBuffer::ready(const bool& ready) { _ready = ready; }
const bool& FrameBuffer::isReady() { return _ready; }
<commit_msg>Exception handlings<commit_after>/*
Copyright (c) 2016,
Dan Bethell, Johannes Saam, Vahan Sosoyan, Brian Scherbinski.
All rights reserved. See COPYING.txt for more details.
*/

#include "FrameBuffer.h"
#include "boost/format.hpp"

using namespace aton;

const std::string chStr::RGBA = "RGBA",
                  chStr::rgb = "rgb",
                  chStr::depth = "depth",
                  chStr::Z = "Z",
                  chStr::N = "N",
                  chStr::P = "P",
                  chStr::_red = ".red",
                  chStr::_green = ".green",
                  chStr::_blue = ".blue",
                  chStr::_X = ".X",
                  chStr::_Y = ".Y",
                  chStr::_Z = ".Z";

// Lightweight color pixel class
RenderColor::RenderColor() { _val[0] = _val[1] = _val[2] = 0.0f; }

float& RenderColor::operator[](int i) { return _val[i]; }
const float& RenderColor::operator[](int i) const { return _val[i]; }

// RenderBuffer class
RenderBuffer::RenderBuffer(const unsigned int& width,
                           const unsigned int& height,
                           const int& spp)
{
    size_t size = width * height;

    switch (spp)
    {
        case 1: // Float channels
            _float_data.resize(size);
            break;
        case 3: // Color Channels
            _color_data.resize(size);
            break;
        case 4: // Color + Alpha channels
            _color_data.resize(size);
            _float_data.resize(size);
            break;
    }
}

// FrameBuffer class
FrameBuffer::FrameBuffer(const double& currentFrame,
                         const int& w,
                         const int& h): _frame(currentFrame),
                                        _width(w),
                                        _height(h),
                                        _progress(0),
                                        _time(0),
                                        _ram(0),
                                        _pram(0),
                                        _ready(false) {}

// Add new buffer
void FrameBuffer::addBuffer(const char* aov,
                            const int& spp)
{
    RenderBuffer buffer(_width, _height, spp);

    _buffers.push_back(buffer);
    _aovs.push_back(aov);
}

// Get writable buffer object
void FrameBuffer::setBufferPix(const int& b,
                               const unsigned int& x,
                               const unsigned int& y,
                               const int& spp,
                               const int& c,
                               const float& pix)
{
    RenderBuffer& rb = _buffers[b];
    unsigned int index = (_width * y) + x;
    if (c < 3 && spp != 1)
        rb._color_data[index][c] = pix;
    else
        rb._float_data[index] = pix;
}

// Get read only buffer object
const float& FrameBuffer::getBufferPix(const int& b,
                                       const unsigned int& x,
                                       const unsigned int& y,
                                       const int& c) const
{
    const RenderBuffer& rb = _buffers[b];
    unsigned int index = (_width * y) + x;
    if (c < 3 && !rb._color_data.empty())
        return rb._color_data[index][c];
    else
        return rb._float_data[index];
}

// Get the current buffer index
int FrameBuffer::getBufferIndex(const Channel& z)
{
    int b_index = 0;
    if (_aovs.size() > 1)
    {
        using namespace chStr;
        std::string layer = getLayerName(z);

        std::vector<std::string>::iterator it;
        for(it = _aovs.begin(); it != _aovs.end(); ++it)
        {
            if (*it == layer)
            {
                b_index = static_cast<int>(it - _aovs.begin());
                break;
            }
            else if (*it == Z && layer == depth)
            {
                b_index = static_cast<int>(it - _aovs.begin());
                break;
            }
        }

    }
    return b_index;
}

// Get the current buffer index
int FrameBuffer::getBufferIndex(const char* aovName)
{
    int b_index = 0;
    if (_aovs.size() > 1)
    {
        std::vector<std::string>::iterator it;
        for(it = _aovs.begin(); it != _aovs.end(); ++it)
        {
            if (*it == aovName)
            {
                b_index = static_cast<int>(it - _aovs.begin());
                break;
            }
        }
    }
    return b_index;
}

// Get N buffer/aov name name
const char* FrameBuffer::getBufferName(const int& index)
{
    const char* aovName = "";

    if(!_aovs.empty())
        try
        {
            aovName = _aovs.at(index).c_str();
        }
        catch (const std::out_of_range& e)
        {
			//std::cerr << "Out of Range error" << std::endl;
        }
        catch (...)
        {
            std::cerr << "Unexpected error at getting buffer name" << std::endl;
        }

    return aovName;
}

// Get last buffer/aov name
bool FrameBuffer::isFirstBufferName(const char* aovName)
{
    return strcmp(_aovs.front().c_str(), aovName) == 0;;
}

// Check if Frame has been changed
bool FrameBuffer::isFrameChanged(const double& frame)
{
    return frame != _frame;
}

// Check if Aovs has been changed
bool FrameBuffer::isAovsChanged(const std::vector<std::string>& aovs)
{
    return (aovs != _aovs);
}

// Check if Resolution has been changed
bool FrameBuffer::isResolutionChanged(const unsigned int& width,
                                      const unsigned int& height)
{
    return (width != _width && height != _height);
}

// Clear buffers and aovs
void FrameBuffer::clearAll()
{
    _buffers = std::vector<RenderBuffer>();
    _aovs = std::vector<std::string>();
}

// Check if the given buffer/aov name name is exist
bool FrameBuffer::isBufferExist(const char* aovName)
{
    return std::find(_aovs.begin(),
                     _aovs.end(), aovName) != _aovs.end();
}

// Set width of the buffer
void FrameBuffer::setWidth(const int& w) { _width = w; }

// Set height of the buffer
void FrameBuffer::setHeight(const int& h) { _height = h; }

// Get width of the buffer
const int& FrameBuffer::getWidth() { return _width; }

// Get height of the buffer
const int& FrameBuffer::getHeight() { return _height; }

// Get size of the buffers aka AOVs count
size_t FrameBuffer::size() { return _aovs.size(); }

// Resize the buffers
void FrameBuffer::resize(const size_t& s)
{
    _buffers.resize(s);
    _aovs.resize(s);
}

// Set status parameters
void FrameBuffer::setProgress(const long long& progress)
{
    _progress = progress > 100 ? 100 : progress;
}

void FrameBuffer::setRAM(const long long& ram)
{
    int ramGb = static_cast<int>(ram / 1048576);
    _ram = ramGb;
    _pram = ramGb > _pram ? ramGb : _pram;

}
void FrameBuffer::setTime(const int& time,
                          const int& dtime)
{
    _time = dtime > time ? time : time - dtime;
}

// Get status parameters
const long long& FrameBuffer::getProgress() { return _progress; }
const long long& FrameBuffer::getRAM() { return _ram; }
const long long& FrameBuffer::getPRAM() { return _pram; }
const int& FrameBuffer::getTime() { return _time; }

// Set Arnold core version
void FrameBuffer::setArnoldVersion(const int& version)
{
    // Construct a string from the version number passed
    int archV = (version % 10000000) / 1000000;
    int majorV = (version % 1000000) / 10000;
    int minorV = (version % 10000) / 100;
    int fixV = version % 100;

    std::stringstream stream;
    stream << archV << "." << majorV << "." << minorV << "." << fixV;
    _version = stream.str();
}

// Get Arnold core version
const char* FrameBuffer::getArnoldVersion() { return _version.c_str(); }

// Set the frame number of this framebuffer
void FrameBuffer::setFrame(const double& frame) { _frame = frame; }

// Get the frame number of this framebuffer
const double& FrameBuffer::getFrame() { return _frame; }

// Check if this framebuffer is empty
bool FrameBuffer::empty() { return (_buffers.empty() && _aovs.empty()) ; }

// To keep False while writing the buffer
void FrameBuffer::ready(const bool& ready) { _ready = ready; }
const bool& FrameBuffer::isReady() { return _ready; }
<|endoftext|>