<commit_before>/*************************************************************************\
**
**  tOutput.cpp: Functions for output classes tOutput and tLOutput
**
**  (see tOutput.h for a description of these classes)
**
**  $Id: tOutput.cpp,v 1.31 2000-06-05 21:19:16 daniel Exp $
\*************************************************************************/

#include "tOutput.h"

/*************************************************************************\
**
**  Constructor
**
**  The constructor takes two arguments, a pointer to the mesh and
**  a reference to an open input file. It reads the base name for the
**  output files from the input file, and opens and initializes these.
**
**  Input: meshPtr -- pointer to a tMesh object (or descendant), assumed
**                    valid
**         infile -- reference to an open input file, assumed valid
**
\*************************************************************************/
template< class tSubNode >
tOutput<tSubNode>::tOutput( tMesh<tSubNode> * meshPtr, tInputFile &infile )
{
   assert( meshPtr > 0 );
   m = meshPtr;

   infile.ReadItem( baseName, "OUTFILENAME" );

   CreateAndOpenFile( &nodeofs, ".nodes" );
   CreateAndOpenFile( &edgofs, ".edges" );
   CreateAndOpenFile( &triofs, ".tri" );
   CreateAndOpenFile( &zofs, ".z" );
   CreateAndOpenFile( &vaofs, ".varea" );

}

/*************************************************************************\
**
**  tOutput::CreateAndOpenFile
**
**  Opens the output file stream pointed to by theOFStream, giving it the
**  name <baseName><extension>, and checks to make sure that the ofstream
**  is valid.
**
**  Input:  theOFStream -- ptr to an ofstream object
**          extension -- file name extension (e.g., ".nodes")
**  Output: theOFStream is initialized to create an open output file
**  Assumes: extension is a null-terminated string, and the length of
**           baseName plus extension doesn't exceed kMaxNameSize+6
**           (ie, the extension is expected to be <= 6 characters)
**
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::CreateAndOpenFile( ofstream *theOFStream,
                                           char *extension )
{
   char fullName[kMaxNameSize+6];  // name of file to be created

   strcpy( fullName, baseName );
   strcat( fullName, extension );
   theOFStream->open( fullName );

   if( !theOFStream->good() )
       ReportFatalError(
           "I can't create files for output. Storage space may be exhausted.");

}

/*************************************************************************\
**
**  tOutput::WriteOutput
**
**  This function writes information about the mesh to four files called
**  name.nodes, name.edges, name.tri, and name.z, where "name" is a
**  name that the user has specified in the input file and which is
**  stored in the data member baseName.
**
**  Input: time -- time of the current output time-slice
**  Output: the node, edge, and triangle ID numbers are modified so that
**          they are numbered according to their position on the list
**  Assumes: the four file ofstreams have been opened by the constructor
**           and are valid
**
**  TODO: deal with option for once-only printing of mesh when mesh not
**        deforming
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::WriteOutput( double time )
{
   tMeshListIter<tSubNode> niter( m->getNodeList() ); // node list iterator
   tMeshListIter<tEdge> eiter( m->getEdgeList() );    // edge list iterator
   tPtrListIter<tTriangle> titer( m->getTriList() );     // tri list iterator
   tNode * cn;       // current node
   tEdge * ce;       // current edge
   tTriangle * ct;   // current triangle
   int id;           // id of element (node, edge, or triangle)
   int nnodes = m->getNodeList()->getSize();  // # of nodes on list
   int nedges = m->getEdgeList()->getSize();  // "    edges "
   int ntri = m->getTriList()->getSize();     // "    triangles "

   cout << "tOutput::WriteOutput()\n" << flush;

   // Renumber IDs in order by position on list
   for( cn=niter.FirstP(), id=0; id<nnodes; cn=niter.NextP(), id++ )
       cn->setID( id );
   for( ce=eiter.FirstP(), id=0; id<nedges; ce=eiter.NextP(), id++ )
       ce->setID( id );
   for( ct=titer.FirstP(), id=0; id<ntri; ct=titer.NextP(), id++ )
       ct->setID( id );

   // Write node file, z file, and varea file
   nodeofs << " " << time << endl << nnodes << endl;
   zofs << " " << time << endl << nnodes << endl;
   vaofs << " " << time << endl << nnodes << endl;
   for( cn=niter.FirstP(); !(niter.AtEnd()); cn=niter.NextP() )
   {
      nodeofs << cn->getX() << " " << cn->getY() << " "
              << cn->getEdg()->getID() << " " << cn->getBoundaryFlag() << endl;
      zofs << cn->getZ() << endl;
      vaofs << cn->getVArea() << endl;
   }

   // Write edge file
   edgofs << " " << time << endl << nedges << endl;
   for( ce=eiter.FirstP(); !(eiter.AtEnd()); ce=eiter.NextP() )
      edgofs << ce->getOriginPtrNC()->getID() << " "
             << ce->getDestinationPtrNC()->getID() << " "
             << ce->getCCWEdg()->getID() << endl;

   // Write triangle file
   int i;
   triofs << " " << time << endl << ntri << endl;
   for( ct=titer.FirstP(); !(titer.AtEnd()); ct=titer.NextP() )
   {
      for( i=0; i<=2; i++ )
          triofs << ct->pPtr(i)->getID() << " ";
      for( i=0; i<=2; i++ )
      {
          if( ct->tPtr(i) ) triofs << ct->tPtr(i)->getID() << " ";
          else triofs << "-1 ";
      }
      triofs << ct->ePtr(0)->getID() << " "
             << ct->ePtr(1)->getID() << " "
             << ct->ePtr(2)->getID() << endl;
   }

   // Call virtual function to write any additional data
   WriteNodeData( time );

}

/*************************************************************************\
**
**  tOutput::WriteNodeData
**
**  This is a virtual function which can be overridden to write any
**  additional node data. The base class version does nothing.
**
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::WriteNodeData( double time )
{}

/*************************************************************************\
**
**  tLOutput constructor
**
**  Creates and opens a series of files for drainage areas, slopes, etc.
**
**  Modifications:
**    - 1/00 added "opOpt" and creation of veg output file (GT)
**    - added flow depth output file (GT 1/00)
\*************************************************************************/
template< class tSubNode >
tLOutput<tSubNode>::tLOutput( tMesh<tSubNode> *meshPtr, tInputFile &infile )
        : tOutput<tSubNode>( meshPtr, infile )  // call base-class constructor
{
   int opOpt;  // Optional modules: only output stuff when needed

   CreateAndOpenFile( &drareaofs, ".area" );
   CreateAndOpenFile( &netofs, ".net" );
   CreateAndOpenFile( &slpofs, ".slp" );
   CreateAndOpenFile( &qofs, ".q" );
   CreateAndOpenFile( &layofs, ".lay" );
   CreateAndOpenFile( &texofs, ".tx" );
   if( (opOpt = infile.ReadItem( opOpt, "OPTVEG" ) ) )
       CreateAndOpenFile( &vegofs, ".veg" );
   if( (opOpt = infile.ReadItem( opOpt, "OPTKINWAVE" ) ) )
       CreateAndOpenFile( &flowdepofs, ".dep" );
   if( (optTSOutput = infile.ReadItem( optTSOutput, "OPTTSOUTPUT" ) ) )
       CreateAndOpenFile( &volsofs, ".vols" );

}

/*************************************************************************\
**
**  tLOutput::WriteNodeData
**
**  This overridden virtual function writes output for tLNodes, including
**  drainage areas, flow pathways, slopes, discharges, layer info, etc.
**
**  Modifications:
**    - 1/00 added output to veg output file (GT)
**    - added output of flow depth; made slope output for all nodes (GT 1/00)
\*************************************************************************/
//TODO: should output boundary points as well so they'll map up with nodes
// for plotting. Means changing getSlope so it returns zero if flowedg
// undefined
template< class tSubNode >
void tLOutput<tSubNode>::WriteNodeData( double time )
{
   tMeshListIter<tSubNode> ni( m->getNodeList() ); // node list iterator
   tSubNode *cn;   // current node
   int nActiveNodes = m->getNodeList()->getActiveSize(); // # active nodes
   int nnodes = m->getNodeList()->getSize();             // total # nodes
   int i, j;      // counters

   // Write current time in each file
   drareaofs << " " << time << "\n " << nActiveNodes << endl;
   netofs << " " << time << "\n " << nActiveNodes << endl;
   slpofs << " " << time << "\n " << nnodes << endl;
   qofs << " " << time << "\n " << nnodes << endl;
   layofs << " " << time << "\n" << nActiveNodes << endl;
   texofs << " " << time << "\n" << nnodes << endl;
   if( vegofs.good() ) vegofs << " " << time << "\n" << nnodes << endl;
   if( flowdepofs.good() ) flowdepofs << " " << time << "\n" << nnodes << endl;

   // Write data, including layer info
   for( cn = ni.FirstP(); ni.IsActive(); cn = ni.NextP() )
   {
      assert( cn>0 );
      drareaofs << cn->getDrArea() << endl;
      if( cn->getDownstrmNbr() )
          netofs << cn->getDownstrmNbr()->getID() << endl;
      layofs << " " << cn->getNumLayer() << endl;
      i=0;
      while(i<cn->getNumLayer()){
         layofs << cn->getLayerCtime(i) << " " << cn->getLayerRtime(i) << " " << cn->getLayerEtime(i) << endl;
         layofs << cn->getLayerDepth(i) << " " << cn->getLayerErody(i) << " " << cn->getLayerSed(i) << endl;
         j=0;
         while(j<cn->getNumg()){
            layofs << cn->getLayerDgrade(i,j) << " ";
            j++;
         }
         layofs << endl;
         i++;
      }
   }

   // Write discharge, vegetation, & texture data
   for( cn = ni.FirstP(); !(ni.AtEnd()); cn = ni.NextP() )
   {
      if( !cn->getBoundaryFlag() ) slpofs << cn->getSlope() << endl;
      else slpofs << 0 << endl;
      qofs << cn->getQ() << endl;
      if( vegofs.good() ) vegofs << cn->getVegCover().getVeg() << endl;
      if( flowdepofs.good() )
          flowdepofs << cn->getHydrDepth() << endl;
      if( cn->getNumg()>1 ) // temporary hack TODO
      {
            texofs << cn->getLayerDgrade(0,0)/cn->getLayerDepth(0) << endl;
      }

   }

}

/*************************************************************************\
**
**  tOutput::WriteTSOutput
**  This function writes the total volume of the DEM above the datum to
**  a file called name.vols, where "name" is a name that the user has
**  specified in the input file and which is stored in the data member
**  baseName.
**
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::WriteTSOutput( double time )
{
   tMeshListIter<tSubNode> niter( m->getNodeList() ); // node list iterator

   tNode * cn;       // current node

   double volume = 0;

   cout << "tOutput::WriteTSOutput()\n" << flush;

   for( cn=niter.FirstP(); !(niter.AtEnd()); cn=niter.NextP() )
       volume += cn->getZ()*cn->getVArea();

   volsofs << volume << endl;

}

<commit_msg>*** empty log message ***<commit_after>/*************************************************************************\
**
**  tOutput.cpp: Functions for output classes tOutput and tLOutput
**
**  (see tOutput.h for a description of these classes)
**
**  $Id: tOutput.cpp,v 1.32 2000-06-05 21:20:36 daniel Exp $
\*************************************************************************/

#include "tOutput.h"

/*************************************************************************\
**
**  Constructor
**
**  The constructor takes two arguments, a pointer to the mesh and
**  a reference to an open input file. It reads the base name for the
**  output files from the input file, and opens and initializes these.
**
**  Input: meshPtr -- pointer to a tMesh object (or descendant), assumed
**                    valid
**         infile -- reference to an open input file, assumed valid
**
\*************************************************************************/
template< class tSubNode >
tOutput<tSubNode>::tOutput( tMesh<tSubNode> * meshPtr, tInputFile &infile )
{
   assert( meshPtr > 0 );
   m = meshPtr;

   infile.ReadItem( baseName, "OUTFILENAME" );

   CreateAndOpenFile( &nodeofs, ".nodes" );
   CreateAndOpenFile( &edgofs, ".edges" );
   CreateAndOpenFile( &triofs, ".tri" );
   CreateAndOpenFile( &zofs, ".z" );
   CreateAndOpenFile( &vaofs, ".varea" );

}

/*************************************************************************\
**
**  tOutput::CreateAndOpenFile
**
**  Opens the output file stream pointed to by theOFStream, giving it the
**  name <baseName><extension>, and checks to make sure that the ofstream
**  is valid.
**
**  Input:  theOFStream -- ptr to an ofstream object
**          extension -- file name extension (e.g., ".nodes")
**  Output: theOFStream is initialized to create an open output file
**  Assumes: extension is a null-terminated string, and the length of
**           baseName plus extension doesn't exceed kMaxNameSize+6
**           (ie, the extension is expected to be <= 6 characters)
**
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::CreateAndOpenFile( ofstream *theOFStream,
                                           char *extension )
{
   char fullName[kMaxNameSize+6];  // name of file to be created

   strcpy( fullName, baseName );
   strcat( fullName, extension );
   theOFStream->open( fullName );

   if( !theOFStream->good() )
       ReportFatalError(
           "I can't create files for output. Storage space may be exhausted.");

}

/*************************************************************************\
**
**  tOutput::WriteOutput
**
**  This function writes information about the mesh to four files called
**  name.nodes, name.edges, name.tri, and name.z, where "name" is a
**  name that the user has specified in the input file and which is
**  stored in the data member baseName.
**
**  Input: time -- time of the current output time-slice
**  Output: the node, edge, and triangle ID numbers are modified so that
**          they are numbered according to their position on the list
**  Assumes: the four file ofstreams have been opened by the constructor
**           and are valid
**
**  TODO: deal with option for once-only printing of mesh when mesh not
**        deforming
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::WriteOutput( double time )
{
   tMeshListIter<tSubNode> niter( m->getNodeList() ); // node list iterator
   tMeshListIter<tEdge> eiter( m->getEdgeList() );    // edge list iterator
   tPtrListIter<tTriangle> titer( m->getTriList() );     // tri list iterator
   tNode * cn;       // current node
   tEdge * ce;       // current edge
   tTriangle * ct;   // current triangle
   int id;           // id of element (node, edge, or triangle)
   int nnodes = m->getNodeList()->getSize();  // # of nodes on list
   int nedges = m->getEdgeList()->getSize();  // "    edges "
   int ntri = m->getTriList()->getSize();     // "    triangles "

   cout << "tOutput::WriteOutput()\n" << flush;

   // Renumber IDs in order by position on list
   for( cn=niter.FirstP(), id=0; id<nnodes; cn=niter.NextP(), id++ )
       cn->setID( id );
   for( ce=eiter.FirstP(), id=0; id<nedges; ce=eiter.NextP(), id++ )
       ce->setID( id );
   for( ct=titer.FirstP(), id=0; id<ntri; ct=titer.NextP(), id++ )
       ct->setID( id );

   // Write node file, z file, and varea file
   nodeofs << " " << time << endl << nnodes << endl;
   zofs << " " << time << endl << nnodes << endl;
   vaofs << " " << time << endl << nnodes << endl;
   for( cn=niter.FirstP(); !(niter.AtEnd()); cn=niter.NextP() )
   {
      nodeofs << cn->getX() << " " << cn->getY() << " "
              << cn->getEdg()->getID() << " " << cn->getBoundaryFlag() << endl;
      zofs << cn->getZ() << endl;
      vaofs << cn->getVArea() << endl;
   }

   // Write edge file
   edgofs << " " << time << endl << nedges << endl;
   for( ce=eiter.FirstP(); !(eiter.AtEnd()); ce=eiter.NextP() )
      edgofs << ce->getOriginPtrNC()->getID() << " "
             << ce->getDestinationPtrNC()->getID() << " "
             << ce->getCCWEdg()->getID() << endl;

   // Write triangle file
   int i;
   triofs << " " << time << endl << ntri << endl;
   for( ct=titer.FirstP(); !(titer.AtEnd()); ct=titer.NextP() )
   {
      for( i=0; i<=2; i++ )
          triofs << ct->pPtr(i)->getID() << " ";
      for( i=0; i<=2; i++ )
      {
          if( ct->tPtr(i) ) triofs << ct->tPtr(i)->getID() << " ";
          else triofs << "-1 ";
      }
      triofs << ct->ePtr(0)->getID() << " "
             << ct->ePtr(1)->getID() << " "
             << ct->ePtr(2)->getID() << endl;
   }

   // Call virtual function to write any additional data
   WriteNodeData( time );

}

/*************************************************************************\
**
**  tOutput::WriteNodeData
**
**  This is a virtual function which can be overridden to write any
**  additional node data. The base class version does nothing.
**
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::WriteNodeData( double time )
{}

/*************************************************************************\
**
**  tLOutput constructor
**
**  Creates and opens a series of files for drainage areas, slopes, etc.
**
**  Modifications:
**    - 1/00 added "opOpt" and creation of veg output file (GT)
**    - added flow depth output file (GT 1/00)
\*************************************************************************/
template< class tSubNode >
tLOutput<tSubNode>::tLOutput( tMesh<tSubNode> *meshPtr, tInputFile &infile )
        : tOutput<tSubNode>( meshPtr, infile )  // call base-class constructor
{
   int opOpt;  // Optional modules: only output stuff when needed

   CreateAndOpenFile( &drareaofs, ".area" );
   CreateAndOpenFile( &netofs, ".net" );
   CreateAndOpenFile( &slpofs, ".slp" );
   CreateAndOpenFile( &qofs, ".q" );
   CreateAndOpenFile( &layofs, ".lay" );
   CreateAndOpenFile( &texofs, ".tx" );
   if( (opOpt = infile.ReadItem( opOpt, "OPTVEG" ) ) )
       CreateAndOpenFile( &vegofs, ".veg" );
   if( (opOpt = infile.ReadItem( opOpt, "OPTKINWAVE" ) ) )
       CreateAndOpenFile( &flowdepofs, ".dep" );
   if( (int optTSOutput = infile.ReadItem( optTSOutput, "OPTTSOUTPUT" ) ) )
       CreateAndOpenFile( &volsofs, ".vols" );

}

/*************************************************************************\
**
**  tLOutput::WriteNodeData
**
**  This overridden virtual function writes output for tLNodes, including
**  drainage areas, flow pathways, slopes, discharges, layer info, etc.
**
**  Modifications:
**    - 1/00 added output to veg output file (GT)
**    - added output of flow depth; made slope output for all nodes (GT 1/00)
\*************************************************************************/
//TODO: should output boundary points as well so they'll map up with nodes
// for plotting. Means changing getSlope so it returns zero if flowedg
// undefined
template< class tSubNode >
void tLOutput<tSubNode>::WriteNodeData( double time )
{
   tMeshListIter<tSubNode> ni( m->getNodeList() ); // node list iterator
   tSubNode *cn;   // current node
   int nActiveNodes = m->getNodeList()->getActiveSize(); // # active nodes
   int nnodes = m->getNodeList()->getSize();             // total # nodes
   int i, j;      // counters

   // Write current time in each file
   drareaofs << " " << time << "\n " << nActiveNodes << endl;
   netofs << " " << time << "\n " << nActiveNodes << endl;
   slpofs << " " << time << "\n " << nnodes << endl;
   qofs << " " << time << "\n " << nnodes << endl;
   layofs << " " << time << "\n" << nActiveNodes << endl;
   texofs << " " << time << "\n" << nnodes << endl;
   if( vegofs.good() ) vegofs << " " << time << "\n" << nnodes << endl;
   if( flowdepofs.good() ) flowdepofs << " " << time << "\n" << nnodes << endl;

   // Write data, including layer info
   for( cn = ni.FirstP(); ni.IsActive(); cn = ni.NextP() )
   {
      assert( cn>0 );
      drareaofs << cn->getDrArea() << endl;
      if( cn->getDownstrmNbr() )
          netofs << cn->getDownstrmNbr()->getID() << endl;
      layofs << " " << cn->getNumLayer() << endl;
      i=0;
      while(i<cn->getNumLayer()){
         layofs << cn->getLayerCtime(i) << " " << cn->getLayerRtime(i) << " " << cn->getLayerEtime(i) << endl;
         layofs << cn->getLayerDepth(i) << " " << cn->getLayerErody(i) << " " << cn->getLayerSed(i) << endl;
         j=0;
         while(j<cn->getNumg()){
            layofs << cn->getLayerDgrade(i,j) << " ";
            j++;
         }
         layofs << endl;
         i++;
      }
   }

   // Write discharge, vegetation, & texture data
   for( cn = ni.FirstP(); !(ni.AtEnd()); cn = ni.NextP() )
   {
      if( !cn->getBoundaryFlag() ) slpofs << cn->getSlope() << endl;
      else slpofs << 0 << endl;
      qofs << cn->getQ() << endl;
      if( vegofs.good() ) vegofs << cn->getVegCover().getVeg() << endl;
      if( flowdepofs.good() )
          flowdepofs << cn->getHydrDepth() << endl;
      if( cn->getNumg()>1 ) // temporary hack TODO
      {
            texofs << cn->getLayerDgrade(0,0)/cn->getLayerDepth(0) << endl;
      }

   }

}

/*************************************************************************\
**
**  tOutput::WriteTSOutput
**  This function writes the total volume of the DEM above the datum to
**  a file called name.vols, where "name" is a name that the user has
**  specified in the input file and which is stored in the data member
**  baseName.
**
\*************************************************************************/
template< class tSubNode >
void tOutput<tSubNode>::WriteTSOutput( double time )
{
   tMeshListIter<tSubNode> niter( m->getNodeList() ); // node list iterator

   tNode * cn;       // current node

   double volume = 0;

   cout << "tOutput::WriteTSOutput()\n" << flush;

   for( cn=niter.FirstP(); !(niter.AtEnd()); cn=niter.NextP() )
       volume += cn->getZ()*cn->getVArea();

   volsofs << volume << endl;

}

<|endoftext|>


<commit_before>// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "bootstrapper.h"
#include "debug.h"
#include "scopeinfo.h"

namespace v8 {
namespace internal {

JSBuiltinsObject* Context::builtins() {
  GlobalObject* object = global();
  if (object->IsJSGlobalObject()) {
    return JSGlobalObject::cast(object)->builtins();
  } else {
    ASSERT(object->IsJSBuiltinsObject());
    return JSBuiltinsObject::cast(object);
  }
}

Context* Context::global_context() {
  // Fast case: the global object for this context has been set.  In
  // that case, the global object has a direct pointer to the global
  // context.
  if (global()->IsGlobalObject()) {
    return global()->global_context();
  }

  // During bootstrapping, the global object might not be set and we
  // have to search the context chain to find the global context.
  ASSERT(Isolate::Current()->bootstrapper()->IsActive());
  Context* current = this;
  while (!current->IsGlobalContext()) {
    JSFunction* closure = JSFunction::cast(current->closure());
    current = Context::cast(closure->context());
  }
  return current;
}

JSObject* Context::global_proxy() {
  return global_context()->global_proxy_object();
}

void Context::set_global_proxy(JSObject* object) {
  global_context()->set_global_proxy_object(object);
}

Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
                               int* index_, PropertyAttributes* attributes) {
  Isolate* isolate = GetIsolate();
  Handle<Context> context(this, isolate);

  bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
  *index_ = -1;
  *attributes = ABSENT;

  if (FLAG_trace_contexts) {
    PrintF("Context::Lookup(");
    name->ShortPrint();
    PrintF(")\n");
  }

  do {
    if (FLAG_trace_contexts) {
      PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
      if (context->IsGlobalContext()) PrintF(" (global context)");
      PrintF("\n");
    }

    // check extension/with object
    if (context->has_extension()) {
      Handle<JSObject> extension = Handle<JSObject>(context->extension(),
                                                    isolate);
      // Context extension objects needs to behave as if they have no
      // prototype.  So even if we want to follow prototype chains, we
      // need to only do a local lookup for context extension objects.
      if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
          extension->IsJSContextExtensionObject()) {
        *attributes = extension->GetLocalPropertyAttribute(*name);
      } else {
        *attributes = extension->GetPropertyAttribute(*name);
      }
      if (*attributes != ABSENT) {
        // property found
        if (FLAG_trace_contexts) {
          PrintF("=> found property in context object %p\n",
                 reinterpret_cast<void*>(*extension));
        }
        return extension;
      }
    }

    if (context->is_function_context()) {
      // we have context-local slots

      // check non-parameter locals in context
      Handle<SerializedScopeInfo> scope_info(
          context->closure()->shared()->scope_info(), isolate);
      Variable::Mode mode;
      int index = scope_info->ContextSlotIndex(*name, &mode);
      ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
      if (index >= 0) {
        // slot found
        if (FLAG_trace_contexts) {
          PrintF("=> found local in context slot %d (mode = %d)\n",
                 index, mode);
        }
        *index_ = index;
        // Note: Fixed context slots are statically allocated by the compiler.
        // Statically allocated variables always have a statically known mode,
        // which is the mode with which they were declared when added to the
        // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
        // declared variables that were introduced through declaration nodes)
        // must not appear here.
        switch (mode) {
          case Variable::INTERNAL:  // fall through
          case Variable::VAR: *attributes = NONE; break;
          case Variable::CONST: *attributes = READ_ONLY; break;
          case Variable::DYNAMIC: UNREACHABLE(); break;
          case Variable::DYNAMIC_GLOBAL: UNREACHABLE(); break;
          case Variable::DYNAMIC_LOCAL: UNREACHABLE(); break;
          case Variable::TEMPORARY: UNREACHABLE(); break;
        }
        return context;
      }

      // check parameter locals in context
      int param_index = scope_info->ParameterIndex(*name);
      if (param_index >= 0) {
        // slot found.
        int index = scope_info->ContextSlotIndex(
            isolate->heap()->arguments_shadow_symbol(), NULL);
        ASSERT(index >= 0);  // arguments must exist and be in the heap context
        Handle<JSObject> arguments(JSObject::cast(context->get(index)),
                                   isolate);
        ASSERT(arguments->HasLocalProperty(isolate->heap()->length_symbol()));
        if (FLAG_trace_contexts) {
          PrintF("=> found parameter %d in arguments object\n", param_index);
        }
        *index_ = param_index;
        *attributes = NONE;
        return arguments;
      }

      // check intermediate context (holding only the function name variable)
      if (follow_context_chain) {
        int index = scope_info->FunctionContextSlotIndex(*name);
        if (index >= 0) {
          // slot found
          if (FLAG_trace_contexts) {
            PrintF("=> found intermediate function in context slot %d\n",
                   index);
          }
          *index_ = index;
          *attributes = READ_ONLY;
          return context;
        }
      }
    }

    // proceed with enclosing context
    if (context->IsGlobalContext()) {
      follow_context_chain = false;
    } else if (context->is_function_context()) {
      context = Handle<Context>(Context::cast(context->closure()->context()),
                                isolate);
    } else {
      context = Handle<Context>(context->previous(), isolate);
    }
  } while (follow_context_chain);

  // slot not found
  if (FLAG_trace_contexts) {
    PrintF("=> no property/slot found\n");
  }
  return Handle<Object>::null();
}

bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
  Context* context = this;

  // Check that there is no local with the given name in contexts
  // before the global context and check that there are no context
  // extension objects (conservative check for with statements).
  while (!context->IsGlobalContext()) {
    // Check if the context is a potentially a with context.
    if (context->has_extension()) return false;

    // Not a with context so it must be a function context.
    ASSERT(context->is_function_context());

    // Check non-parameter locals.
    Handle<SerializedScopeInfo> scope_info(
        context->closure()->shared()->scope_info());
    Variable::Mode mode;
    int index = scope_info->ContextSlotIndex(*name, &mode);
    ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
    if (index >= 0) return false;

    // Check parameter locals.
    int param_index = scope_info->ParameterIndex(*name);
    if (param_index >= 0) return false;

    // Check context only holding the function name variable.
    index = scope_info->FunctionContextSlotIndex(*name);
    if (index >= 0) return false;
    context = Context::cast(context->closure()->context());
  }

  // No local or potential with statement found so the variable is
  // global unless it is shadowed by an eval-introduced variable.
  return true;
}

void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
                                   bool* outer_scope_calls_non_strict_eval) {
  Context* context = this;
  while (true) {
    Handle<SerializedScopeInfo> scope_info(
        context->closure()->shared()->scope_info());
    if (scope_info->CallsEval()) {
      *outer_scope_calls_eval = true;
      if (!scope_info->IsStrictMode()) {
        // No need to go further since the answers will not change
        // from here.
        *outer_scope_calls_non_strict_eval = true;
        return;
      }
    }
    if (context->IsGlobalContext()) break;
    context = Context::cast(context->closure()->context());
  }
}

void Context::AddOptimizedFunction(JSFunction* function) {
  ASSERT(IsGlobalContext());
#ifdef DEBUG
  Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
  while (!element->IsUndefined()) {
    CHECK(element != function);
    element = JSFunction::cast(element)->next_function_link();
  }

  CHECK(function->next_function_link()->IsUndefined());

  // Check that the context belongs to the weak global contexts list.
  bool found = false;
  Object* context = GetHeap()->global_contexts_list();
  while (!context->IsUndefined()) {
    if (context == this) {
      found = true;
      break;
    }
    context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
  }
  CHECK(found);
#endif
  function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST));
  set(OPTIMIZED_FUNCTIONS_LIST, function);
}

void Context::RemoveOptimizedFunction(JSFunction* function) {
  ASSERT(IsGlobalContext());
  Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
  JSFunction* prev = NULL;
  while (!element->IsUndefined()) {
    JSFunction* element_function = JSFunction::cast(element);
    ASSERT(element_function->next_function_link()->IsUndefined() ||
           element_function->next_function_link()->IsJSFunction());
    if (element_function == function) {
      if (prev == NULL) {
        set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link());
      } else {
        prev->set_next_function_link(element_function->next_function_link());
      }
      element_function->set_next_function_link(GetHeap()->undefined_value());
      return;
    }
    prev = element_function;
    element = element_function->next_function_link();
  }
  UNREACHABLE();
}

Object* Context::OptimizedFunctionsListHead() {
  ASSERT(IsGlobalContext());
  return get(OPTIMIZED_FUNCTIONS_LIST);
}

void Context::ClearOptimizedFunctions() {
  set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value());
}

#ifdef DEBUG
bool Context::IsBootstrappingOrContext(Object* object) {
  // During bootstrapping we allow all objects to pass as
  // contexts. This is necessary to fix circular dependencies.
  return Isolate::Current()->bootstrapper()->IsActive() || object->IsContext();
}

bool Context::IsBootstrappingOrGlobalObject(Object* object) {
  // During bootstrapping we allow all objects to pass as global
  // objects. This is necessary to fix circular dependencies.
  Isolate* isolate = Isolate::Current();
  return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
      isolate->bootstrapper()->IsActive() ||
      object->IsGlobalObject();
}
#endif

} }  // namespace v8::internal
<commit_msg>Remove wrong assert to fix a debug crash with arguments object.<commit_after>// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "bootstrapper.h"
#include "debug.h"
#include "scopeinfo.h"

namespace v8 {
namespace internal {

JSBuiltinsObject* Context::builtins() {
  GlobalObject* object = global();
  if (object->IsJSGlobalObject()) {
    return JSGlobalObject::cast(object)->builtins();
  } else {
    ASSERT(object->IsJSBuiltinsObject());
    return JSBuiltinsObject::cast(object);
  }
}

Context* Context::global_context() {
  // Fast case: the global object for this context has been set.  In
  // that case, the global object has a direct pointer to the global
  // context.
  if (global()->IsGlobalObject()) {
    return global()->global_context();
  }

  // During bootstrapping, the global object might not be set and we
  // have to search the context chain to find the global context.
  ASSERT(Isolate::Current()->bootstrapper()->IsActive());
  Context* current = this;
  while (!current->IsGlobalContext()) {
    JSFunction* closure = JSFunction::cast(current->closure());
    current = Context::cast(closure->context());
  }
  return current;
}

JSObject* Context::global_proxy() {
  return global_context()->global_proxy_object();
}

void Context::set_global_proxy(JSObject* object) {
  global_context()->set_global_proxy_object(object);
}

Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
                               int* index_, PropertyAttributes* attributes) {
  Isolate* isolate = GetIsolate();
  Handle<Context> context(this, isolate);

  bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
  *index_ = -1;
  *attributes = ABSENT;

  if (FLAG_trace_contexts) {
    PrintF("Context::Lookup(");
    name->ShortPrint();
    PrintF(")\n");
  }

  do {
    if (FLAG_trace_contexts) {
      PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
      if (context->IsGlobalContext()) PrintF(" (global context)");
      PrintF("\n");
    }

    // check extension/with object
    if (context->has_extension()) {
      Handle<JSObject> extension = Handle<JSObject>(context->extension(),
                                                    isolate);
      // Context extension objects needs to behave as if they have no
      // prototype.  So even if we want to follow prototype chains, we
      // need to only do a local lookup for context extension objects.
      if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
          extension->IsJSContextExtensionObject()) {
        *attributes = extension->GetLocalPropertyAttribute(*name);
      } else {
        *attributes = extension->GetPropertyAttribute(*name);
      }
      if (*attributes != ABSENT) {
        // property found
        if (FLAG_trace_contexts) {
          PrintF("=> found property in context object %p\n",
                 reinterpret_cast<void*>(*extension));
        }
        return extension;
      }
    }

    if (context->is_function_context()) {
      // we have context-local slots

      // check non-parameter locals in context
      Handle<SerializedScopeInfo> scope_info(
          context->closure()->shared()->scope_info(), isolate);
      Variable::Mode mode;
      int index = scope_info->ContextSlotIndex(*name, &mode);
      ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
      if (index >= 0) {
        // slot found
        if (FLAG_trace_contexts) {
          PrintF("=> found local in context slot %d (mode = %d)\n",
                 index, mode);
        }
        *index_ = index;
        // Note: Fixed context slots are statically allocated by the compiler.
        // Statically allocated variables always have a statically known mode,
        // which is the mode with which they were declared when added to the
        // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
        // declared variables that were introduced through declaration nodes)
        // must not appear here.
        switch (mode) {
          case Variable::INTERNAL:  // fall through
          case Variable::VAR: *attributes = NONE; break;
          case Variable::CONST: *attributes = READ_ONLY; break;
          case Variable::DYNAMIC: UNREACHABLE(); break;
          case Variable::DYNAMIC_GLOBAL: UNREACHABLE(); break;
          case Variable::DYNAMIC_LOCAL: UNREACHABLE(); break;
          case Variable::TEMPORARY: UNREACHABLE(); break;
        }
        return context;
      }

      // check parameter locals in context
      int param_index = scope_info->ParameterIndex(*name);
      if (param_index >= 0) {
        // slot found.
        int index = scope_info->ContextSlotIndex(
            isolate->heap()->arguments_shadow_symbol(), NULL);
        ASSERT(index >= 0);  // arguments must exist and be in the heap context
        Handle<JSObject> arguments(JSObject::cast(context->get(index)),
                                   isolate);
        if (FLAG_trace_contexts) {
          PrintF("=> found parameter %d in arguments object\n", param_index);
        }
        *index_ = param_index;
        *attributes = NONE;
        return arguments;
      }

      // check intermediate context (holding only the function name variable)
      if (follow_context_chain) {
        int index = scope_info->FunctionContextSlotIndex(*name);
        if (index >= 0) {
          // slot found
          if (FLAG_trace_contexts) {
            PrintF("=> found intermediate function in context slot %d\n",
                   index);
          }
          *index_ = index;
          *attributes = READ_ONLY;
          return context;
        }
      }
    }

    // proceed with enclosing context
    if (context->IsGlobalContext()) {
      follow_context_chain = false;
    } else if (context->is_function_context()) {
      context = Handle<Context>(Context::cast(context->closure()->context()),
                                isolate);
    } else {
      context = Handle<Context>(context->previous(), isolate);
    }
  } while (follow_context_chain);

  // slot not found
  if (FLAG_trace_contexts) {
    PrintF("=> no property/slot found\n");
  }
  return Handle<Object>::null();
}

bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
  Context* context = this;

  // Check that there is no local with the given name in contexts
  // before the global context and check that there are no context
  // extension objects (conservative check for with statements).
  while (!context->IsGlobalContext()) {
    // Check if the context is a potentially a with context.
    if (context->has_extension()) return false;

    // Not a with context so it must be a function context.
    ASSERT(context->is_function_context());

    // Check non-parameter locals.
    Handle<SerializedScopeInfo> scope_info(
        context->closure()->shared()->scope_info());
    Variable::Mode mode;
    int index = scope_info->ContextSlotIndex(*name, &mode);
    ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
    if (index >= 0) return false;

    // Check parameter locals.
    int param_index = scope_info->ParameterIndex(*name);
    if (param_index >= 0) return false;

    // Check context only holding the function name variable.
    index = scope_info->FunctionContextSlotIndex(*name);
    if (index >= 0) return false;
    context = Context::cast(context->closure()->context());
  }

  // No local or potential with statement found so the variable is
  // global unless it is shadowed by an eval-introduced variable.
  return true;
}

void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
                                   bool* outer_scope_calls_non_strict_eval) {
  Context* context = this;
  while (true) {
    Handle<SerializedScopeInfo> scope_info(
        context->closure()->shared()->scope_info());
    if (scope_info->CallsEval()) {
      *outer_scope_calls_eval = true;
      if (!scope_info->IsStrictMode()) {
        // No need to go further since the answers will not change
        // from here.
        *outer_scope_calls_non_strict_eval = true;
        return;
      }
    }
    if (context->IsGlobalContext()) break;
    context = Context::cast(context->closure()->context());
  }
}

void Context::AddOptimizedFunction(JSFunction* function) {
  ASSERT(IsGlobalContext());
#ifdef DEBUG
  Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
  while (!element->IsUndefined()) {
    CHECK(element != function);
    element = JSFunction::cast(element)->next_function_link();
  }

  CHECK(function->next_function_link()->IsUndefined());

  // Check that the context belongs to the weak global contexts list.
  bool found = false;
  Object* context = GetHeap()->global_contexts_list();
  while (!context->IsUndefined()) {
    if (context == this) {
      found = true;
      break;
    }
    context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
  }
  CHECK(found);
#endif
  function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST));
  set(OPTIMIZED_FUNCTIONS_LIST, function);
}

void Context::RemoveOptimizedFunction(JSFunction* function) {
  ASSERT(IsGlobalContext());
  Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
  JSFunction* prev = NULL;
  while (!element->IsUndefined()) {
    JSFunction* element_function = JSFunction::cast(element);
    ASSERT(element_function->next_function_link()->IsUndefined() ||
           element_function->next_function_link()->IsJSFunction());
    if (element_function == function) {
      if (prev == NULL) {
        set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link());
      } else {
        prev->set_next_function_link(element_function->next_function_link());
      }
      element_function->set_next_function_link(GetHeap()->undefined_value());
      return;
    }
    prev = element_function;
    element = element_function->next_function_link();
  }
  UNREACHABLE();
}

Object* Context::OptimizedFunctionsListHead() {
  ASSERT(IsGlobalContext());
  return get(OPTIMIZED_FUNCTIONS_LIST);
}

void Context::ClearOptimizedFunctions() {
  set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value());
}

#ifdef DEBUG
bool Context::IsBootstrappingOrContext(Object* object) {
  // During bootstrapping we allow all objects to pass as
  // contexts. This is necessary to fix circular dependencies.
  return Isolate::Current()->bootstrapper()->IsActive() || object->IsContext();
}

bool Context::IsBootstrappingOrGlobalObject(Object* object) {
  // During bootstrapping we allow all objects to pass as global
  // objects. This is necessary to fix circular dependencies.
  Isolate* isolate = Isolate::Current();
  return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
      isolate->bootstrapper()->IsActive() ||
      object->IsGlobalObject();
}
#endif

} }  // namespace v8::internal
<|endoftext|>


<commit_before>// Copyright (c) 2011-2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include "function.h"
#include "function_call.h"
#include "function_statistics.h"
#include "native_function.h"
#include "normal_function.h"
#include "profile_writer.h"
#include "profiler.h"
#include "public_function.h"

namespace amx_profiler {

Profiler::Profiler(AMX *amx, DebugInfo debug_info, bool enable_call_graph)
	: amx_(amx)
	, debug_info_(debug_info)
	, call_graph_enabled_(enable_call_graph)
{
}

Profiler::~Profiler() {
	for (auto address_stats : address_to_stats_) {
		delete address_stats.second;
	}
	for (auto function : functions_) {
		delete function;
	}
}

std::vector<FunctionStatistics*> Profiler::GetProfile() const {
	std::vector<FunctionStatistics*> profile;
	for (auto address_stats : address_to_stats_) {
		profile.push_back(address_stats.second);
	}
	return profile;
}

void Profiler::WriteProfile(ProfileWriter *writer) const {
	writer->Write(GetProfile());
}

int Profiler::amx_Debug(int (AMXAPI *debug)(AMX *amx)) {
	cell prev_frame = amx_->stp;
	if (!call_stack_.IsEmpty()) {
		prev_frame = call_stack_.top()->frame();
	}
	if (amx_->frm < prev_frame) {
		if (call_stack_.top()->frame() != amx_->frm) {
			auto address = static_cast<ucell>(amx_->cip) - 2*sizeof(cell);
			if (address_to_stats_.find(address) == address_to_stats_.end()) {
				auto fn = new NormalFunction(address, debug_info_);
				functions_.insert(fn);
				address_to_stats_.insert(std::make_pair(address, new FunctionStatistics(fn)));
			}
			BeginFunction(address, amx_->frm);
		}
	} else if (amx_->frm > prev_frame) {
		if (typeid(*call_stack_.top()->function()) == typeid(NormalFunction)) {
			EndFunction();
		}
	}
	if (debug != 0) {
		return debug(amx_);
	}
	return AMX_ERR_NONE;
}

int Profiler::amx_Callback(cell index, cell *result, cell *params,
	int (AMXAPI *callback)(AMX *amx, cell index, cell *result, cell *params)) {
	if (callback == 0) {
		callback = ::amx_Callback;
	}
	if (index >= 0) {
		auto address = GetNativeAddress(index);
		if (address_to_stats_.find(address) == address_to_stats_.end()) {
			auto fn = new NativeFunction(amx_, index);
			functions_.insert(fn);
			address_to_stats_.insert(std::make_pair(address, new FunctionStatistics(fn)));
		}
		BeginFunction(address, amx_->frm);
		int error = callback(amx_, index, result, params);
		EndFunction(address);
		return error;
	} else {
		return callback(amx_, index, result, params);
	}
}

int Profiler::amx_Exec(cell *retval, int index,
	int (AMXAPI *exec)(AMX *amx, cell *retval, int index)) {
	if (exec == 0) {
		exec = ::amx_Exec;
	}
	if (index >= 0 || index == AMX_EXEC_MAIN) {
		auto address = GetPublicAddress(index);
		if (address_to_stats_.find(address) == address_to_stats_.end()) {
			auto fn = new PublicFunction(amx_, index);
			functions_.insert(fn);
			address_to_stats_.insert(std::make_pair(address, new FunctionStatistics(fn)));
		}
		BeginFunction(address, amx_->stk - 3*sizeof(cell));
		int error = exec(amx_, retval, index);
		EndFunction(address);
		return error;
	} else {
		return exec(amx_, retval, index);
	}
}

ucell Profiler::GetNativeAddress(cell index) {
	if (index >= 0) {
		auto hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
		auto natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->natives);
		return natives[index].address;
	}
	assert(0 && "Invalid native index");
	return 0;
}

ucell Profiler::GetPublicAddress(cell index) {
	auto hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
	if (index >= 0) {
		auto publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
		return publics[index].address;
	} else if (index == AMX_EXEC_MAIN) {
		return hdr->cip;
	}
	assert(0 && "Invalid public index");
	return 0;
}

void Profiler::BeginFunction(ucell address, ucell frm) {
	assert(address != 0);
	auto info_it = address_to_stats_.find(address);
	assert(info_it != address_to_stats_.end());
	auto stats = info_it->second;
	stats->num_calls()++;
	call_stack_.Push(stats->function(), frm);
	if (call_graph_enabled_) {
		call_graph_.root()->AddCallee(stats)->MakeRoot();
	}
}

void Profiler::EndFunction(ucell address) {
	assert(!call_stack_.IsEmpty());
	assert(address == 0 || address_to_stats_.find(address) != address_to_stats_.end());
	while (true) {
		auto old_top = call_stack_.Pop();
		auto old_top_it = address_to_stats_.find(old_top.function()->address());
		assert(old_top_it != address_to_stats_.end());
		if (old_top.IsRecursive()) {
			old_top_it->second->child_time() -= old_top.timer()->child_time<Nanoseconds>();
		} else {
			old_top_it->second->total_time() += old_top.timer()->total_time<Nanoseconds>();
		}
		if (!call_stack_.IsEmpty()) {
			auto top = call_stack_.top();
			auto top_it = address_to_stats_.find(top->function()->address());
			assert(top_it != address_to_stats_.end());
			top_it->second->child_time() += old_top.timer()->total_time<Nanoseconds>();
		}
		if (call_graph_enabled_) {
			assert(call_graph_.root() != call_graph_.sentinel());
			call_graph_.set_root(call_graph_.root()->caller());
		}
		if (address == 0 || (old_top.function()->address() == address)) {
			break;
		}
	}
}

} // namespace amx_profiler
<commit_msg>Change variable name<commit_after>// Copyright (c) 2011-2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include "function.h"
#include "function_call.h"
#include "function_statistics.h"
#include "native_function.h"
#include "normal_function.h"
#include "profile_writer.h"
#include "profiler.h"
#include "public_function.h"

namespace amx_profiler {

Profiler::Profiler(AMX *amx, DebugInfo debug_info, bool enable_call_graph)
	: amx_(amx)
	, debug_info_(debug_info)
	, call_graph_enabled_(enable_call_graph)
{
}

Profiler::~Profiler() {
	for (auto address_stats : address_to_stats_) {
		delete address_stats.second;
	}
	for (auto function : functions_) {
		delete function;
	}
}

std::vector<FunctionStatistics*> Profiler::GetProfile() const {
	std::vector<FunctionStatistics*> profile;
	for (auto address_stats : address_to_stats_) {
		profile.push_back(address_stats.second);
	}
	return profile;
}

void Profiler::WriteProfile(ProfileWriter *writer) const {
	writer->Write(GetProfile());
}

int Profiler::amx_Debug(int (AMXAPI *debug)(AMX *amx)) {
	cell prev_frame = amx_->stp;
	if (!call_stack_.IsEmpty()) {
		prev_frame = call_stack_.top()->frame();
	}
	if (amx_->frm < prev_frame) {
		if (call_stack_.top()->frame() != amx_->frm) {
			auto address = static_cast<ucell>(amx_->cip) - 2*sizeof(cell);
			if (address_to_stats_.find(address) == address_to_stats_.end()) {
				auto fn = new NormalFunction(address, debug_info_);
				functions_.insert(fn);
				address_to_stats_.insert(std::make_pair(address, new FunctionStatistics(fn)));
			}
			BeginFunction(address, amx_->frm);
		}
	} else if (amx_->frm > prev_frame) {
		if (typeid(*call_stack_.top()->function()) == typeid(NormalFunction)) {
			EndFunction();
		}
	}
	if (debug != 0) {
		return debug(amx_);
	}
	return AMX_ERR_NONE;
}

int Profiler::amx_Callback(cell index, cell *result, cell *params,
	int (AMXAPI *callback)(AMX *amx, cell index, cell *result, cell *params)) {
	if (callback == 0) {
		callback = ::amx_Callback;
	}
	if (index >= 0) {
		auto address = GetNativeAddress(index);
		if (address_to_stats_.find(address) == address_to_stats_.end()) {
			auto fn = new NativeFunction(amx_, index);
			functions_.insert(fn);
			address_to_stats_.insert(std::make_pair(address, new FunctionStatistics(fn)));
		}
		BeginFunction(address, amx_->frm);
		int error = callback(amx_, index, result, params);
		EndFunction(address);
		return error;
	} else {
		return callback(amx_, index, result, params);
	}
}

int Profiler::amx_Exec(cell *retval, int index,
	int (AMXAPI *exec)(AMX *amx, cell *retval, int index)) {
	if (exec == 0) {
		exec = ::amx_Exec;
	}
	if (index >= 0 || index == AMX_EXEC_MAIN) {
		auto address = GetPublicAddress(index);
		if (address_to_stats_.find(address) == address_to_stats_.end()) {
			auto fn = new PublicFunction(amx_, index);
			functions_.insert(fn);
			address_to_stats_.insert(std::make_pair(address, new FunctionStatistics(fn)));
		}
		BeginFunction(address, amx_->stk - 3*sizeof(cell));
		int error = exec(amx_, retval, index);
		EndFunction(address);
		return error;
	} else {
		return exec(amx_, retval, index);
	}
}

ucell Profiler::GetNativeAddress(cell index) {
	if (index >= 0) {
		auto hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
		auto natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->natives);
		return natives[index].address;
	}
	assert(0 && "Invalid native index");
	return 0;
}

ucell Profiler::GetPublicAddress(cell index) {
	auto hdr = reinterpret_cast<AMX_HEADER*>(amx_->base);
	if (index >= 0) {
		auto publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx_->base + hdr->publics);
		return publics[index].address;
	} else if (index == AMX_EXEC_MAIN) {
		return hdr->cip;
	}
	assert(0 && "Invalid public index");
	return 0;
}

void Profiler::BeginFunction(ucell address, ucell frm) {
	assert(address != 0);
	auto stats_it = address_to_stats_.find(address);
	assert(stats_it != address_to_stats_.end());
	auto stats = stats_it->second;
	stats->num_calls()++;
	call_stack_.Push(stats->function(), frm);
	if (call_graph_enabled_) {
		call_graph_.root()->AddCallee(stats)->MakeRoot();
	}
}

void Profiler::EndFunction(ucell address) {
	assert(!call_stack_.IsEmpty());
	assert(address == 0 || address_to_stats_.find(address) != address_to_stats_.end());
	while (true) {
		auto old_top = call_stack_.Pop();
		auto old_top_it = address_to_stats_.find(old_top.function()->address());
		assert(old_top_it != address_to_stats_.end());
		if (old_top.IsRecursive()) {
			old_top_it->second->child_time() -= old_top.timer()->child_time<Nanoseconds>();
		} else {
			old_top_it->second->total_time() += old_top.timer()->total_time<Nanoseconds>();
		}
		if (!call_stack_.IsEmpty()) {
			auto top = call_stack_.top();
			auto top_it = address_to_stats_.find(top->function()->address());
			assert(top_it != address_to_stats_.end());
			top_it->second->child_time() += old_top.timer()->total_time<Nanoseconds>();
		}
		if (call_graph_enabled_) {
			assert(call_graph_.root() != call_graph_.sentinel());
			call_graph_.set_root(call_graph_.root()->caller());
		}
		if (address == 0 || (old_top.function()->address() == address)) {
			break;
		}
	}
}

} // namespace amx_profiler
<|endoftext|>


<commit_before>//
//  Core.hpp
//  ee_x
//
//  Created by Zinge on 5/9/17.
//
//

#ifndef EE_X_CORE_HEADER_HPP_
#define EE_X_CORE_HEADER_HPP_

#include "ee/Macro.hpp"
#include "ee/core/Logger.hpp"
#include "ee/core/LogLevel.hpp"

#if defined(EE_X_ANDROID)
#include "ee/core/JniUtils.hpp"
#elif defined(EE_X_IOS) || defined(EE_X_OSX)
#if defined(__OBJC__)
#import "ee/core/EEPluginManager.h"
#endif // __OBJC__
#endif // EE_X_ANDROID

namespace ee {
using core::Logger;
using core::LogLevel;

#if defined(EE_X_ANDROID)
using core::JniUtils;
#endif // EE_X_ANDROID
} // namespace ee

#endif /* EE_X_CORE_HEADER_HPP_ */
<commit_msg>Update header.<commit_after>//
//  Core.hpp
//  ee_x
//
//  Created by Zinge on 5/9/17.
//
//

#ifndef EE_X_CORE_HEADER_HPP_
#define EE_X_CORE_HEADER_HPP_

#include "ee/Macro.hpp"
#include "ee/core/Logger.hpp"
#include "ee/core/LogLevel.hpp"
#include "ee/core/Metrics.hpp"

#if defined(EE_X_ANDROID)
#include "ee/core/JniUtils.hpp"
#elif defined(EE_X_IOS) || defined(EE_X_OSX)
#if defined(__OBJC__)
#import "ee/core/EEPluginManager.h"
#import "ee/core/EEMetrics.h"
#endif // __OBJC__
#endif // EE_X_ANDROID

namespace ee {
using core::Logger;
using core::LogLevel;

#if defined(EE_X_ANDROID)
using core::JniUtils;
#endif // EE_X_ANDROID
} // namespace ee

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


<commit_before>#include "bindings.h"
#include "endpoint.h"
#include "device.h"
#include "transfer.h"

namespace NodeUsb {
	Persistent<FunctionTemplate> Endpoint::constructor_template;

	Endpoint::Endpoint(Handle<Object> _v8device, Device* _device, const libusb_endpoint_descriptor* _endpoint_descriptor, uint32_t _idx_endpoint) : ObjectWrap() {
		v8device = Persistent<Object>::New(_v8device);
		device = _device;
		descriptor = _endpoint_descriptor;
		// if bit[7] of endpoint address is set => ENDPOINT_IN (device to host), else: ENDPOINT_OUT (host to device)
		endpoint_type = (descriptor->bEndpointAddress & (1 << 7)) ? (LIBUSB_ENDPOINT_IN) : (LIBUSB_ENDPOINT_OUT);
		// bit[0] and bit[1] of bmAttributes masks transfer_type; 3 = 0000 0011
		transfer_type = (libusb_transfer_type)(3 & descriptor->bmAttributes);
		idx_endpoint = _idx_endpoint;
	}

	Endpoint::~Endpoint() {
		// TODO Close
		v8device.Dispose();
		DEBUG("Endpoint object destroyed")
	}

	void Endpoint::Initalize(Handle<Object> target) {
		DEBUG("Entering...")
		HandleScope  scope;
		Local<FunctionTemplate> t = FunctionTemplate::New(Endpoint::New);

		// Constructor
		t->InstanceTemplate()->SetInternalFieldCount(1);
		t->SetClassName(String::NewSymbol("Endpoint"));
		Endpoint::constructor_template = Persistent<FunctionTemplate>::New(t);

		Local<ObjectTemplate> instance_template = t->InstanceTemplate();

		// Constants
		// no constants at the moment

		// Properties
		instance_template->SetAccessor(V8STR("__endpointType"), Endpoint::EndpointTypeGetter);
		instance_template->SetAccessor(V8STR("__transferType"), Endpoint::TransferTypeGetter);
		instance_template->SetAccessor(V8STR("__maxIsoPacketSize"), Endpoint::MaxIsoPacketSizeGetter);
		instance_template->SetAccessor(V8STR("__maxPacketSize"), Endpoint::MaxPacketSizeGetter);

		// methods exposed to node.js
		NODE_SET_PROTOTYPE_METHOD(t, "getExtraData", Endpoint::GetExtraData);
		NODE_SET_PROTOTYPE_METHOD(t, "transfer", Endpoint::Transfer);

		// Make it visible in JavaScript
		target->Set(String::NewSymbol("Endpoint"), t->GetFunction());
		DEBUG("Leave")
	}

	Handle<Value> Endpoint::New(const Arguments& args) {
		HandleScope scope;
		DEBUG("New Endpoint object created")

		if (args.Length() != 4 || !args[0]->IsObject() || !args[1]->IsUint32() || !args[2]->IsUint32()|| !args[3]->IsUint32()) {
			THROW_BAD_ARGS("Device::New argument is invalid. [object:device, uint32_t:idx_interface, uint32_t:idx_alt_setting, uint32_t:idx_endpoint]!")
		}

		// make local value reference to first parameter
		Local<Object> device = Local<Object>::Cast(args[0]);
		Device *dev = ObjectWrap::Unwrap<Device>(device);
		uint32_t idxInterface  = args[1]->Uint32Value();
		uint32_t idxAltSetting = args[2]->Uint32Value();
		uint32_t idxEndpoint   = args[3]->Uint32Value();

		const libusb_endpoint_descriptor *libusbEndpointDescriptor = &((dev->config_descriptor->interface[idxInterface]).altsetting[idxAltSetting]).endpoint[idxEndpoint];

		// create new Endpoint object
		Endpoint *endpoint = new Endpoint(device, dev, libusbEndpointDescriptor, idxEndpoint);
		// initalize handle

#define LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(name) \
		args.This()->Set(V8STR(#name), Uint32::New(endpoint->descriptor->name));
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bLength)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bDescriptorType)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bEndpointAddress)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bmAttributes)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(wMaxPacketSize)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bInterval)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bRefresh)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bSynchAddress)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(extra_length)

		// wrap created Endpoint object to v8
		endpoint->Wrap(args.This());

		return args.This();
	}

	Handle<Value> Endpoint::EndpointTypeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())

		return scope.Close(Integer::New(self->endpoint_type));
	}

	Handle<Value> Endpoint::TransferTypeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())

		return scope.Close(Integer::New(self->transfer_type));
	}

	Handle<Value> Endpoint::MaxPacketSizeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())
		int r = 0;

		CHECK_USB((r = libusb_get_max_packet_size(self->device->device, self->descriptor->bEndpointAddress)), scope)

		return scope.Close(Integer::New(r));
	}

	Handle<Value> Endpoint::MaxIsoPacketSizeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())
		int r = 0;

		CHECK_USB((r = libusb_get_max_iso_packet_size(self->device->device, self->descriptor->bEndpointAddress)), scope)

		return scope.Close(Integer::New(r));
	}

	Handle<Value> Endpoint::GetExtraData(const Arguments& args) {
		LOCAL(Endpoint, self, args.This())

		int m = (*self->descriptor).extra_length;

		Local<Array> r = Array::New(m);

		for (int i = 0; i < m; i++) {
		  uint32_t c = (*self->descriptor).extra[i];

		  r->Set(i, Uint32::New(c));
		}

		return scope.Close(r);
	}

	Handle<Value> Endpoint::Transfer(const Arguments& args){
		LOCAL(Endpoint, self, args.This())

		CHECK_USB(self->device->openHandle(), scope);

		unsigned length;
		unsigned char *buf;

		//args: buffer/size, callback

		if (args.Length() < 2 || !args[1]->IsFunction()) {
			THROW_BAD_ARGS("Transfer missing arguments!")
		}

		BUF_LEN_ARG(args[0]);

		if (modus != self->endpoint_type) {
			THROW_BAD_ARGS("Transfer is used in the wrong direction (IN/OUT) for this endpoint");
		}

		NodeUsb::Transfer* t = Transfer::newTransfer(
			self->transfer_type,
			args.This(),
			self->descriptor->bEndpointAddress,
			buf,
			length,
			self->device->timeout,
			Handle<Function>::Cast(args[1])
		);

		t->submit();

		return Undefined();
	}
}
<commit_msg>Fix endpoint.transfer<commit_after>#include "bindings.h"
#include "endpoint.h"
#include "device.h"
#include "transfer.h"

namespace NodeUsb {
	Persistent<FunctionTemplate> Endpoint::constructor_template;

	Endpoint::Endpoint(Handle<Object> _v8device, Device* _device, const libusb_endpoint_descriptor* _endpoint_descriptor, uint32_t _idx_endpoint) : ObjectWrap() {
		v8device = Persistent<Object>::New(_v8device);
		device = _device;
		descriptor = _endpoint_descriptor;
		// if bit[7] of endpoint address is set => ENDPOINT_IN (device to host), else: ENDPOINT_OUT (host to device)
		endpoint_type = (descriptor->bEndpointAddress & (1 << 7)) ? (LIBUSB_ENDPOINT_IN) : (LIBUSB_ENDPOINT_OUT);
		// bit[0] and bit[1] of bmAttributes masks transfer_type; 3 = 0000 0011
		transfer_type = (libusb_transfer_type)(3 & descriptor->bmAttributes);
		idx_endpoint = _idx_endpoint;
	}

	Endpoint::~Endpoint() {
		// TODO Close
		v8device.Dispose();
		DEBUG("Endpoint object destroyed")
	}

	void Endpoint::Initalize(Handle<Object> target) {
		DEBUG("Entering...")
		HandleScope  scope;
		Local<FunctionTemplate> t = FunctionTemplate::New(Endpoint::New);

		// Constructor
		t->InstanceTemplate()->SetInternalFieldCount(1);
		t->SetClassName(String::NewSymbol("Endpoint"));
		Endpoint::constructor_template = Persistent<FunctionTemplate>::New(t);

		Local<ObjectTemplate> instance_template = t->InstanceTemplate();

		// Constants
		// no constants at the moment

		// Properties
		instance_template->SetAccessor(V8STR("__endpointType"), Endpoint::EndpointTypeGetter);
		instance_template->SetAccessor(V8STR("__transferType"), Endpoint::TransferTypeGetter);
		instance_template->SetAccessor(V8STR("__maxIsoPacketSize"), Endpoint::MaxIsoPacketSizeGetter);
		instance_template->SetAccessor(V8STR("__maxPacketSize"), Endpoint::MaxPacketSizeGetter);

		// methods exposed to node.js
		NODE_SET_PROTOTYPE_METHOD(t, "getExtraData", Endpoint::GetExtraData);
		NODE_SET_PROTOTYPE_METHOD(t, "transfer", Endpoint::Transfer);

		// Make it visible in JavaScript
		target->Set(String::NewSymbol("Endpoint"), t->GetFunction());
		DEBUG("Leave")
	}

	Handle<Value> Endpoint::New(const Arguments& args) {
		HandleScope scope;
		DEBUG("New Endpoint object created")

		if (args.Length() != 4 || !args[0]->IsObject() || !args[1]->IsUint32() || !args[2]->IsUint32()|| !args[3]->IsUint32()) {
			THROW_BAD_ARGS("Device::New argument is invalid. [object:device, uint32_t:idx_interface, uint32_t:idx_alt_setting, uint32_t:idx_endpoint]!")
		}

		// make local value reference to first parameter
		Local<Object> device = Local<Object>::Cast(args[0]);
		Device *dev = ObjectWrap::Unwrap<Device>(device);
		uint32_t idxInterface  = args[1]->Uint32Value();
		uint32_t idxAltSetting = args[2]->Uint32Value();
		uint32_t idxEndpoint   = args[3]->Uint32Value();

		const libusb_endpoint_descriptor *libusbEndpointDescriptor = &((dev->config_descriptor->interface[idxInterface]).altsetting[idxAltSetting]).endpoint[idxEndpoint];

		// create new Endpoint object
		Endpoint *endpoint = new Endpoint(device, dev, libusbEndpointDescriptor, idxEndpoint);
		// initalize handle

#define LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(name) \
		args.This()->Set(V8STR(#name), Uint32::New(endpoint->descriptor->name));
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bLength)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bDescriptorType)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bEndpointAddress)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bmAttributes)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(wMaxPacketSize)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bInterval)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bRefresh)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(bSynchAddress)
		LIBUSB_ENDPOINT_DESCRIPTOR_STRUCT_TO_V8(extra_length)

		// wrap created Endpoint object to v8
		endpoint->Wrap(args.This());

		return args.This();
	}

	Handle<Value> Endpoint::EndpointTypeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())

		return scope.Close(Integer::New(self->endpoint_type));
	}

	Handle<Value> Endpoint::TransferTypeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())

		return scope.Close(Integer::New(self->transfer_type));
	}

	Handle<Value> Endpoint::MaxPacketSizeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())
		int r = 0;

		CHECK_USB((r = libusb_get_max_packet_size(self->device->device, self->descriptor->bEndpointAddress)), scope)

		return scope.Close(Integer::New(r));
	}

	Handle<Value> Endpoint::MaxIsoPacketSizeGetter(Local<String> property, const AccessorInfo &info) {
		LOCAL(Endpoint, self, info.Holder())
		int r = 0;

		CHECK_USB((r = libusb_get_max_iso_packet_size(self->device->device, self->descriptor->bEndpointAddress)), scope)

		return scope.Close(Integer::New(r));
	}

	Handle<Value> Endpoint::GetExtraData(const Arguments& args) {
		LOCAL(Endpoint, self, args.This())

		int m = (*self->descriptor).extra_length;

		Local<Array> r = Array::New(m);

		for (int i = 0; i < m; i++) {
		  uint32_t c = (*self->descriptor).extra[i];

		  r->Set(i, Uint32::New(c));
		}

		return scope.Close(r);
	}

	Handle<Value> Endpoint::Transfer(const Arguments& args){
		LOCAL(Endpoint, self, args.This())

		CHECK_USB(self->device->openHandle(), scope);

		unsigned length;
		unsigned char *buf;

		//args: buffer/size, callback

		if (args.Length() < 2 || !args[1]->IsFunction()) {
			THROW_BAD_ARGS("Transfer missing arguments!")
		}

		BUF_LEN_ARG(args[0]);

		if (modus != self->endpoint_type) {
			THROW_BAD_ARGS("Transfer is used in the wrong direction (IN/OUT) for this endpoint");
		}

		DEBUG_OPT("Submitting transfer %x (%i: %p)", modus, length, buf);

		NodeUsb::Transfer* t = Transfer::newTransfer(
			self->transfer_type,
			self->v8device,
			self->descriptor->bEndpointAddress,
			buf,
			length,
			self->device->timeout,
			Handle<Function>::Cast(args[1])
		);

		t->submit();

		return Undefined();
	}
}
<|endoftext|>


<commit_before>#include "stdafx.h"

#define IS_HANGUL(c)	( (c) >= 0xAC00 && (c) <= 0xD7A3 )
#define IS_HANGUL2(c)	( ( (c) >= 0x3130 && (c) <= 0x318F ) || IS_HANGUL(c) )	// hangul + jamo

#define FONT_MAN_CHAR_W	16
#define FONT_MAN_CHAR_H	16

#define FONT_MAN_FONT_H	16

#define TEX_W		512
#define TEX_H		512

FontMan11 fontMan;

struct FontVertex {
	Vec2 pos;
	Vec2 coord;
};

static Vec2 fontVertAlign[] =
{
	Vec2(0, 0),
	Vec2(0, 1),
	Vec2(1, 0),
	Vec2(1, 1),
};

static BOOL isKorean(int code)
{
	return IS_HANGUL2(code) || code < 0x80;
}

static HFONT CreateAsianFont(int code, int height)
{
	BOOL isK = isKorean(code);
	const char *fontName = isK ? "GulimChe" : "MS Gothic";
	const DWORD charset = isK ? HANGUL_CHARSET : SHIFTJIS_CHARSET;
	return CreateFontA(height,			// Height Of Font
		0,								// Width Of Font
		0,								// Angle Of Escapement
		0,								// Orientation Angle
		FW_BOLD,						// Font Weight
		FALSE,							// Italic
		FALSE,							// Underline
		FALSE,							// Strikeout
		charset,						// Character Set Identifier
		OUT_TT_PRECIS,					// Output Precision
		CLIP_DEFAULT_PRECIS,			// Clipping Precision
		ANTIALIASED_QUALITY,			// Output Quality
		FF_DONTCARE | DEFAULT_PITCH,	// Family And Pitch
		fontName);						// Font Name
}

FontMan11::FontMan11()
{
	memset(charCache, 0, sizeof(charCache));
	memset(uniToIndex, 0, sizeof(uniToIndex));
	cursor = curX = curY = 0;
	texture = TexMan::INVALID_TMID;
	shader = ShaderMan::INVALID_SMID;
	dirty = false;
}

FontMan11::~FontMan11()
{
	Destroy();
}

bool FontMan11::Init()
{
	bool result = false;
	if (!texSrc.Create(TEX_W, TEX_H)) {
		goto DONE;
	}
	texture = texMan.CreateDynamicTexture("$FontMan", TEX_W, TEX_H);

	static D3D11_INPUT_ELEMENT_DESC elements[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	shader = shaderMan.Create("fx\\font.fx", elements, dimof(elements));

	ibo = afCreateQuadListIndexBuffer(SPRITE_MAX);
	vbo = afCreateDynamicVertexBuffer(SPRITE_MAX * sizeof(FontVertex));

	{
		CD3D11_SAMPLER_DESC descSamp(D3D11_DEFAULT);
		descSamp.AddressU = descSamp.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
		deviceMan11.GetDevice()->CreateSamplerState(&descSamp, &pSamplerState);
		deviceMan11.GetDevice()->CreateDepthStencilState(&CD3D11_DEPTH_STENCIL_DESC(D3D11_DEFAULT), &pDSState);
		CD3D11_BLEND_DESC bdesc(D3D11_DEFAULT);
		bdesc.RenderTarget[0].BlendEnable = TRUE;
		bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
		bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
		bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
		bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
		bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
		bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
		bdesc.RenderTarget[0].RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL;
		deviceMan11.GetDevice()->CreateBlendState(&bdesc, &blendState);
	}

	result = true;
DONE:
	return result;
}

void FontMan11::Destroy()
{
	// TODO: delete texture
//	texMan.Delete(texture);
//	texture = TexMan::INVALID_TMID;

//  shaderMan.Delete(shader);
//	shader = ShaderMan::INVALID_SMID;

	texSrc.Destroy();
	afSafeDeleteBuffer(ibo);
	afSafeDeleteBuffer(vbo);

	SAFE_RELEASE(pSamplerState);
	SAFE_RELEASE(pDSState);
	SAFE_RELEASE(blendState);
}

bool FontMan11::Build(int index, int code)
{
	HFONT font = NULL, fontOld = NULL;
	bool result = false;
	DIB	dib;

	const BOOL applySoftAA = (code <= 0x80) || !isKorean(code);
	int size = applySoftAA ? 2 : 1;

	if (!dib.Create(FONT_MAN_CHAR_W * size, FONT_MAN_CHAR_H * size)) {
		return false;
	}

	font = CreateAsianFont(code, FONT_MAN_FONT_H * size);
	if (!font) {
		return false;
	}

	{
		dib.Clear();
		WCHAR buf[] = { code, '\0' };
		HDC hdc = dib.getDC();
		HFONT oldFont = (HFONT)SelectObject(hdc, font);
		SetTextColor(hdc, RGB(255, 255, 255));
		SetBkColor(hdc, RGB(0, 0, 0));
		TextOutW(hdc, 0, 0, buf, wcslen(buf));
		SelectObject(hdc, (HGDIOBJ)oldFont);

		if (applySoftAA) {
			DIB	dib2;
			if (!dib2.Create(FONT_MAN_CHAR_W, FONT_MAN_CHAR_H)) {
				goto DONE;
			}
			dib.ApplySoftAA(dib2);
			dib2.DibToDXFont();
			dib2.Blt(texSrc, curX, curY);
		} else {
			dib.DibToDXFont();
			dib.Blt(texSrc, curX, curY);
		}
		dirty = true;
		CharCache& cache = charCache[index];
		cache.code = code;
		cache.x = curX;
		cache.y = curY;
		cache.w = FONT_MAN_CHAR_W;
		cache.h = FONT_MAN_CHAR_H;

		curX += FONT_MAN_CHAR_W;
		if (curX >= TEX_W) {
			curX = 0;
			curY += FONT_MAN_CHAR_H;
		}
		if (curY >= TEX_H) {
			curY = 0;
		}
	}

	result = true;
DONE:
	if (font) DeleteObject(font);
	return result;
}

int FontMan11::Cache(int code)
{
	assert(code >= 0 && code <= 0xffff);
	int listIndex = uniToIndex[code];
	int index;
	if (charCache[listIndex].code != code) {
		uniToIndex[code] = cursor;
		index = cursor;
		Build(cursor, code);
		if (++cursor >= LIST_MAX){
			cursor = 0;
		}
	} else {
		index = uniToIndex[code];
	}
	return index;
}

void FontMan11::FlushToTexture()
{
	if (!dirty) {
		return;
	}
	dirty = false;
	texMan.Write(texture, texSrc.ReferPixels());
}

void FontMan11::Render()
{
	if (!numSprites) {
		return;
	}
	static int index[SPRITE_MAX];
	for (int i = 0; i < numSprites; i++) {
		index[i] = Cache(charSprites[i].code);
	}
	FlushToTexture();

	static FontVertex verts[4 * SPRITE_MAX];
	for (int i = 0; i < numSprites; i++) {
		CharSprite& cs = charSprites[i];
		CharCache& cc = charCache[index[i]];
		float xSize = cs.code < 256 ? 0.5f : 1.0f;

		for (int j = 0; j < dimof(fontVertAlign); j++) {
			verts[i * 4 + j].pos = (((cs.pos + fontVertAlign[j] * Vec2(xSize, 1.0f) * Vec2(FONT_MAN_CHAR_W, FONT_MAN_CHAR_H))) * Vec2(2, 2)) / Vec2(SCR_W, SCR_H);
			verts[i * 4 + j].coord = (Vec2((float)cc.x, (float)cc.y) + fontVertAlign[j] * Vec2(xSize, 1.0f) * Vec2(FONT_MAN_CHAR_W, FONT_MAN_CHAR_H)) / Vec2(TEX_W, TEX_H);
		}
	}
	afWriteBuffer(vbo, verts, 4 * numSprites * sizeof(FontVertex));
	shaderMan.Apply(shader);

	float factor[] = { 0, 0, 0, 0 };
	deviceMan11.GetContext()->OMSetDepthStencilState(pDSState, 1);
	deviceMan11.GetContext()->OMSetBlendState(blendState, factor, 0xffffffff);
	deviceMan11.GetContext()->PSSetSamplers(0, 1, &pSamplerState);

	UINT stride = sizeof(FontVertex);
	UINT offset = 0;
	deviceMan11.GetContext()->IASetVertexBuffers(0, 1, &vbo, &stride, &offset);

	ID3D11ShaderResourceView* tx = texMan.Get(texture);
	deviceMan11.GetContext()->PSSetShaderResources(0, 1, &tx);
	afDrawIndexedTriangleList(ibo, numSprites * 6);

	tx = nullptr;
	deviceMan11.GetContext()->PSSetShaderResources(0, 1, &tx);
	deviceMan11.GetContext()->OMSetBlendState(nullptr, nullptr, 0xffffffff);

	numSprites = 0;
}

void FontMan11::DrawChar(Vec2& pos, int code)
{
	int index = Cache(code);
	float xSize = code < 256 ? 0.5f : 1.0f;

	if (numSprites >= SPRITE_MAX) {
		return;
	}

	CharSprite& c = charSprites[numSprites++];
	c.code = code;
	c.pos = pos;

	pos.x += xSize * FONT_MAN_CHAR_W;
}

void FontMan11::DrawString(Vec2 pos, const WCHAR *text)
{
	int len = wcslen(text);
	for (int i = 0; i < len; i++)
	{
		DrawChar(pos, text[i]);
	}
}

extern FontMan11 fontMan;
<commit_msg>correct projection<commit_after>#include "stdafx.h"

#define IS_HANGUL(c)	( (c) >= 0xAC00 && (c) <= 0xD7A3 )
#define IS_HANGUL2(c)	( ( (c) >= 0x3130 && (c) <= 0x318F ) || IS_HANGUL(c) )	// hangul + jamo

#define FONT_MAN_CHAR_W	16
#define FONT_MAN_CHAR_H	16

#define FONT_MAN_FONT_H	16

#define TEX_W		512
#define TEX_H		512

FontMan11 fontMan;

struct FontVertex {
	Vec2 pos;
	Vec2 coord;
};

static Vec2 fontVertAlign[] =
{
	Vec2(0, 0),
	Vec2(1, 0),
	Vec2(0, 1),
	Vec2(1, 1),
};

static BOOL isKorean(int code)
{
	return IS_HANGUL2(code) || code < 0x80;
}

static HFONT CreateAsianFont(int code, int height)
{
	BOOL isK = isKorean(code);
	const char *fontName = isK ? "GulimChe" : "MS Gothic";
	const DWORD charset = isK ? HANGUL_CHARSET : SHIFTJIS_CHARSET;
	return CreateFontA(height,			// Height Of Font
		0,								// Width Of Font
		0,								// Angle Of Escapement
		0,								// Orientation Angle
		FW_BOLD,						// Font Weight
		FALSE,							// Italic
		FALSE,							// Underline
		FALSE,							// Strikeout
		charset,						// Character Set Identifier
		OUT_TT_PRECIS,					// Output Precision
		CLIP_DEFAULT_PRECIS,			// Clipping Precision
		ANTIALIASED_QUALITY,			// Output Quality
		FF_DONTCARE | DEFAULT_PITCH,	// Family And Pitch
		fontName);						// Font Name
}

FontMan11::FontMan11()
{
	memset(charCache, 0, sizeof(charCache));
	memset(uniToIndex, 0, sizeof(uniToIndex));
	cursor = curX = curY = 0;
	texture = TexMan::INVALID_TMID;
	shader = ShaderMan::INVALID_SMID;
	dirty = false;
}

FontMan11::~FontMan11()
{
	Destroy();
}

bool FontMan11::Init()
{
	bool result = false;
	if (!texSrc.Create(TEX_W, TEX_H)) {
		goto DONE;
	}
	texture = texMan.CreateDynamicTexture("$FontMan", TEX_W, TEX_H);

	static D3D11_INPUT_ELEMENT_DESC elements[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	shader = shaderMan.Create("fx\\font.fx", elements, dimof(elements));

	ibo = afCreateQuadListIndexBuffer(SPRITE_MAX);
	vbo = afCreateDynamicVertexBuffer(SPRITE_MAX * sizeof(FontVertex));

	{
		CD3D11_SAMPLER_DESC descSamp(D3D11_DEFAULT);
		descSamp.AddressU = descSamp.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
		deviceMan11.GetDevice()->CreateSamplerState(&descSamp, &pSamplerState);
		deviceMan11.GetDevice()->CreateDepthStencilState(&CD3D11_DEPTH_STENCIL_DESC(D3D11_DEFAULT), &pDSState);
		CD3D11_BLEND_DESC bdesc(D3D11_DEFAULT);
		bdesc.RenderTarget[0].BlendEnable = TRUE;
		bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
		bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
		bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
		bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
		bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
		bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
		bdesc.RenderTarget[0].RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL;
		deviceMan11.GetDevice()->CreateBlendState(&bdesc, &blendState);
	}

	result = true;
DONE:
	return result;
}

void FontMan11::Destroy()
{
	// TODO: delete texture
//	texMan.Delete(texture);
//	texture = TexMan::INVALID_TMID;

//  shaderMan.Delete(shader);
//	shader = ShaderMan::INVALID_SMID;

	texSrc.Destroy();
	afSafeDeleteBuffer(ibo);
	afSafeDeleteBuffer(vbo);

	SAFE_RELEASE(pSamplerState);
	SAFE_RELEASE(pDSState);
	SAFE_RELEASE(blendState);
}

bool FontMan11::Build(int index, int code)
{
	HFONT font = NULL, fontOld = NULL;
	bool result = false;
	DIB	dib;

	const BOOL applySoftAA = (code <= 0x80) || !isKorean(code);
	int size = applySoftAA ? 2 : 1;

	if (!dib.Create(FONT_MAN_CHAR_W * size, FONT_MAN_CHAR_H * size)) {
		return false;
	}

	font = CreateAsianFont(code, FONT_MAN_FONT_H * size);
	if (!font) {
		return false;
	}

	{
		dib.Clear();
		WCHAR buf[] = { code, '\0' };
		HDC hdc = dib.getDC();
		HFONT oldFont = (HFONT)SelectObject(hdc, font);
		SetTextColor(hdc, RGB(255, 255, 255));
		SetBkColor(hdc, RGB(0, 0, 0));
		TextOutW(hdc, 0, 0, buf, wcslen(buf));
		SelectObject(hdc, (HGDIOBJ)oldFont);

		if (applySoftAA) {
			DIB	dib2;
			if (!dib2.Create(FONT_MAN_CHAR_W, FONT_MAN_CHAR_H)) {
				goto DONE;
			}
			dib.ApplySoftAA(dib2);
			dib2.DibToDXFont();
			dib2.Blt(texSrc, curX, curY);
		} else {
			dib.DibToDXFont();
			dib.Blt(texSrc, curX, curY);
		}
		dirty = true;
		CharCache& cache = charCache[index];
		cache.code = code;
		cache.x = curX;
		cache.y = curY;
		cache.w = FONT_MAN_CHAR_W;
		cache.h = FONT_MAN_CHAR_H;

		curX += FONT_MAN_CHAR_W;
		if (curX >= TEX_W) {
			curX = 0;
			curY += FONT_MAN_CHAR_H;
		}
		if (curY >= TEX_H) {
			curY = 0;
		}
	}

	result = true;
DONE:
	if (font) DeleteObject(font);
	return result;
}

int FontMan11::Cache(int code)
{
	assert(code >= 0 && code <= 0xffff);
	int listIndex = uniToIndex[code];
	int index;
	if (charCache[listIndex].code != code) {
		uniToIndex[code] = cursor;
		index = cursor;
		Build(cursor, code);
		if (++cursor >= LIST_MAX){
			cursor = 0;
		}
	} else {
		index = uniToIndex[code];
	}
	return index;
}

void FontMan11::FlushToTexture()
{
	if (!dirty) {
		return;
	}
	dirty = false;
	texMan.Write(texture, texSrc.ReferPixels());
}

void FontMan11::Render()
{
	if (!numSprites) {
		return;
	}
	static int index[SPRITE_MAX];
	for (int i = 0; i < numSprites; i++) {
		index[i] = Cache(charSprites[i].code);
	}
	FlushToTexture();

	static FontVertex verts[4 * SPRITE_MAX];
	for (int i = 0; i < numSprites; i++) {
		CharSprite& cs = charSprites[i];
		CharCache& cc = charCache[index[i]];
		float xSize = cs.code < 256 ? 0.5f : 1.0f;

		for (int j = 0; j < dimof(fontVertAlign); j++) {
			verts[i * 4 + j].pos = (((cs.pos + fontVertAlign[j] * Vec2(xSize, 1.0f) * Vec2(FONT_MAN_CHAR_W, FONT_MAN_CHAR_H))) * Vec2(2, 2)) / Vec2(SCR_W, -SCR_H) + Vec2(-1, 1);
			verts[i * 4 + j].coord = (Vec2((float)cc.x, (float)cc.y) + fontVertAlign[j] * Vec2(xSize, 1.0f) * Vec2(FONT_MAN_CHAR_W, FONT_MAN_CHAR_H)) / Vec2(TEX_W, TEX_H);
		}
	}
	afWriteBuffer(vbo, verts, 4 * numSprites * sizeof(FontVertex));
	shaderMan.Apply(shader);

	float factor[] = { 0, 0, 0, 0 };
	deviceMan11.GetContext()->OMSetDepthStencilState(pDSState, 1);
	deviceMan11.GetContext()->OMSetBlendState(blendState, factor, 0xffffffff);
	deviceMan11.GetContext()->PSSetSamplers(0, 1, &pSamplerState);

	UINT stride = sizeof(FontVertex);
	UINT offset = 0;
	deviceMan11.GetContext()->IASetVertexBuffers(0, 1, &vbo, &stride, &offset);

	ID3D11ShaderResourceView* tx = texMan.Get(texture);
	deviceMan11.GetContext()->PSSetShaderResources(0, 1, &tx);
	afDrawIndexedTriangleList(ibo, numSprites * 6);

	tx = nullptr;
	deviceMan11.GetContext()->PSSetShaderResources(0, 1, &tx);
	deviceMan11.GetContext()->OMSetBlendState(nullptr, nullptr, 0xffffffff);

	numSprites = 0;
}

void FontMan11::DrawChar(Vec2& pos, int code)
{
	int index = Cache(code);
	float xSize = code < 256 ? 0.5f : 1.0f;

	if (numSprites >= SPRITE_MAX) {
		return;
	}

	CharSprite& c = charSprites[numSprites++];
	c.code = code;
	c.pos = pos;

	pos.x += xSize * FONT_MAN_CHAR_W;
}

void FontMan11::DrawString(Vec2 pos, const WCHAR *text)
{
	int len = wcslen(text);
	for (int i = 0; i < len; i++)
	{
		DrawChar(pos, text[i]);
	}
}

extern FontMan11 fontMan;
<|endoftext|>


<commit_before>#include "deck.h"
#include <algorithm>

logxx::Log Deck::cLog("Deck");

Deck::Deck() {
}

Deck::~Deck() {
}

std::vector<PlayingCard> Deck::GenerateDeck() {
        std::vector<PlayingCard> deck;
        deck.emplace_back();
        bool reachedEnd(false);
        int i(0);
        while(!reachedEnd){
                PlayingCard newCard(deck[i++]);
                newCard.Next(reachedEnd);
                if (!reachedEnd)
                        deck.push_back(newCard);
        }
        return deck;
}

std::vector<PlayingCard> Deck::FromString(const std::string& s, const std::string& separator) {
        S_LOG("FromString");
        std::vector<PlayingCard> deck;
        size_t startPos (0);
        try {
                while (true){
                        size_t pos = s.find(separator, startPos);
                        if (pos == std::string::npos){
                                deck.emplace_back(s.substr(startPos));
                                break;
                        } else {
                                size_t length = pos - startPos;
                                deck.emplace_back(s.substr(startPos, length));
                                startPos = pos + 1;
                        }
                }
        } catch (const std::exception& e){
                log(logxx::error) << "Can't make a desk from string {" << s << "}: \n" << e.what() << logxx::endl;
                deck.clear();
        }
        return deck;
}

bool operator ==(const Deck& lhs, const Deck& rhs){
        return lhs.deck == rhs.deck;
}

bool operator < (const Deck& lhs, const Deck& rhs){
        return lhs.deck < rhs.deck;
}

void Deck::SetDeck(const std::vector<PlayingCard>& deck) {
        this->deck = deck;
}

const std::vector<PlayingCard>& Deck::GetDeck() const {
        return deck;
}

//void Deck::Mix(std::vector<PlayingCard>& deck, const std::function<size_t(size_t)> &rnd) {
//        size_t first, second;
//        do {
//                first = rnd(deck.size());
//                second = rnd(deck.size());
//        } while (second == first);
//        std::swap(deck[first], deck[second]);
//}

//void Deck::Mix(const std::function<size_t(size_t)>& rnd) {
//        Mix(deck, rnd);
//}
<commit_msg>Removed comments<commit_after>#include "deck.h"
#include <algorithm>

logxx::Log Deck::cLog("Deck");

Deck::Deck() {
}

Deck::~Deck() {
}

std::vector<PlayingCard> Deck::GenerateDeck() {
        std::vector<PlayingCard> deck;
        deck.emplace_back();
        bool reachedEnd(false);
        int i(0);
        while(!reachedEnd){
                PlayingCard newCard(deck[i++]);
                newCard.Next(reachedEnd);
                if (!reachedEnd)
                        deck.push_back(newCard);
        }
        return deck;
}

std::vector<PlayingCard> Deck::FromString(const std::string& s, const std::string& separator) {
        S_LOG("FromString");
        std::vector<PlayingCard> deck;
        size_t startPos (0);
        try {
                while (true){
                        size_t pos = s.find(separator, startPos);
                        if (pos == std::string::npos){
                                deck.emplace_back(s.substr(startPos));
                                break;
                        } else {
                                size_t length = pos - startPos;
                                deck.emplace_back(s.substr(startPos, length));
                                startPos = pos + 1;
                        }
                }
        } catch (const std::exception& e){
                log(logxx::error) << "Can't make a desk from string {" << s << "}: \n" << e.what() << logxx::endl;
                deck.clear();
        }
        return deck;
}

bool operator ==(const Deck& lhs, const Deck& rhs){
        return lhs.deck == rhs.deck;
}

bool operator < (const Deck& lhs, const Deck& rhs){
        return lhs.deck < rhs.deck;
}

void Deck::SetDeck(const std::vector<PlayingCard>& deck) {
        this->deck = deck;
}

const std::vector<PlayingCard>& Deck::GetDeck() const {
        return deck;
}

<|endoftext|>


<commit_before>#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

#include <list>

namespace cnf{

class Clause
{
private:
    int getLFalseLiteral(int atom, bool toValue)
    {
        return toValue ? (-1*atom) : atom;
    }

    void eliminateFalseLiteral(int atom, bool toValue)
    {
        auto literal = getLFalseLiteral(atom,toValue);
        literals.remove(literal);
    }

public:

    Clause(std::list<int> c):literals({c}){}

    const size_t size()
    {
        return literals.size();
    }

    void setAtom(int atom, bool toValue)
    {
        eliminateFalseLiteral(atom,toValue);
    }

private:

    std::list<int> literals;
};

}

TEST_CASE("Clauses")

{
    auto clause = std::make_shared<cnf::Clause>(std::list<int>({1,-2,3}));
    SECTION("Initial Size")
    {
        REQUIRE(clause->size()==3);
    }
    SECTION("Atom Assigned")
    {
        SECTION("Atom not in clause")
        {
            clause->setAtom(4,false);
            REQUIRE(clause->size()==3);
        }
        SECTION("Atom assigned false while literal true in clause")
        {
            clause->setAtom(1,false);
            REQUIRE(clause->size()==2);
        }
        SECTION("Atom assigned true while literal false in clause")
        {
            clause->setAtom(2,true);
            REQUIRE(clause->size()==2);
        }
        SECTION("Atom assigned false while literal false in clause")
        {
            clause->setAtom(2,false);
            REQUIRE(clause->size()==3);
        }
        SECTION("Atom assigned true while literal true in clause")
        {
            clause->setAtom(1,true);
            REQUIRE(clause->size()==3);
        }

    }
}
<commit_msg>Initialistaion and satisfaction checks<commit_after>#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

#include <list>

namespace cnf{

class Clause
{
private:
    int translasteAtomAssignmentToLiteral(int atom, bool toValue)
    {
        return toValue ? atom : (-1*atom);
    }

    void eliminateFalseLiteral(int atom, bool toValue)
    {
        auto literal = translasteAtomAssignmentToLiteral(atom, !toValue);
        literals.remove(literal);
    }

    void checkIfSatisfiedByAssignment(int atom, bool toValue)
    {
        auto literal = translasteAtomAssignmentToLiteral(atom, toValue);
        satisfied = std::find(literals.begin(), literals.end(), literal) != literals.end();
    }

public:

    Clause(std::list<int> c):literals({c})
    {
        trim();
    }

    void trim()
    {
        literals.sort([](int first, int second){return abs(first) < abs(second);});
        literals.unique();
        auto before = literals.size();
        literals.unique([](int first, int second){return abs(first) == abs(second);});
        satisfied = before != literals.size();
    }

    const size_t size()
    {
        return literals.size();
    }

    void setAtom(int atom, bool toValue)
    {
        eliminateFalseLiteral(atom, toValue);
        checkIfSatisfiedByAssignment(atom, toValue);
    }

    bool isEmpty()
    {
        return size() == 0;
    }

    bool isUnitClause()
    {
        return size() == 1;
    }

    bool isSatisfied()
    {
        return satisfied;
    }

private:

    std::list<int> literals;
    bool satisfied = false;
};

}

TEST_CASE("Clauses")
{
    SECTION("Unit Clauses have one literal")
    {
        auto unitClause = std::make_shared<cnf::Clause>(std::list<int>({1}));
        REQUIRE(unitClause->isUnitClause());
        SECTION("Unit clause becomes unsatisfiable by atom assignment")
        {
            unitClause->setAtom(1,false);
            REQUIRE(unitClause->isEmpty());
        }
        SECTION("Unit clause satisfied by atom assignment")
        {
            unitClause->setAtom(1,true);
            REQUIRE(unitClause->isSatisfied());
        }
    }
    SECTION("Atom Assigned")
    {
        auto clause = std::make_shared<cnf::Clause>(std::list<int>({1,-2,3}));
        SECTION("Initial Size")
        {
            REQUIRE(clause->size()==3);
        }
        SECTION("Clause with active literals is not empty")
        {
            REQUIRE(!clause->isEmpty());
        }
        SECTION("Setting an Atom not in clause has no effect")
        {
            clause->setAtom(4,false);
            REQUIRE(clause->size()==3);
        }
        SECTION("Atom assigned false eliminates true literal")
        {
            clause->setAtom(1,false);
            REQUIRE(clause->size()==2);
        }
        SECTION("Atom assigned true eliminates false literal")
        {
            clause->setAtom(2,true);
            REQUIRE(clause->size()==2);
        }
        SECTION("Atom assigned true satisfies clause")
        {
            clause->setAtom(1,true);
            REQUIRE(clause->isSatisfied());
        }
        SECTION("Atom assigned false does not satisfy clause")
        {
            clause->setAtom(1,false);
            REQUIRE(!clause->isSatisfied());
        }
        SECTION("Atom assigned false satisfies the clause")
        {
            clause->setAtom(2,false);
            REQUIRE(clause->isSatisfied());
        }
        SECTION("Clause with multiple literals is not a Unit Clause")
        {
            REQUIRE(!clause->isUnitClause());
            SECTION("but becomes unit through variable elimination")
            {
                clause->setAtom(1,false);
                clause->setAtom(2,true);
                REQUIRE(clause->isUnitClause());
            }
        }
    }
    SECTION("Initialise")
    {

        SECTION("Initial Size")
        {
            auto clause = std::make_shared<cnf::Clause>(std::list<int>({1,-2,3}));
            REQUIRE(clause->size()==3);
        }
        SECTION("Initial Size Trimed")
        {
            auto clause = std::make_shared<cnf::Clause>(std::list<int>({1,-2,3,-2,1}));
            REQUIRE(clause->size()==3);
        }
        SECTION("Clause that contains a literal and its negation is trivially satisfied")
        {
            auto clause = std::make_shared<cnf::Clause>(std::list<int>({1,-2,-1}));
            REQUIRE(clause->isSatisfied());
        }
    }
}
<|endoftext|>