<commit_before>/*************************************************************************\
**
**  tOutput.cpp: Functions for output objects
**
**
**
**  $Id: tOutput.cpp,v 1.4 1998-02-02 17:54:18 gtucker Exp $
\*************************************************************************/

#include "tOutput.h"

/*************************************************************************\
**
**  Constructor
**
**  The constructor takes two arguments, a pointer to the grid 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: gridPtr -- pointer to a tGrid object (or descendant), assumed
**                    valid
**         infile -- reference to an open input file, assumed valid
**
\*************************************************************************/
template< class tSubNode >
tOutput<tSubNode>::tOutput( tGrid<tSubNode> * gridPtr, tInputFile &infile )
{
   //Xchar fullName[kMaxNameSize+6];

   assert( gridPtr > 0 );
   g = gridPtr;

   infile.ReadItem( baseName, "OUTFILENAME" );
/*X   strcpy( fullName, baseName );
   strcat( fullName, ".nodes" );
   nodeofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".edges" );
   edgofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".tri" );
   triofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".z" );
   zofs.open( fullName );

   if( !nodeofs.good() || !edgofs.good() || !triofs.good() || !zofs.good() )
       ReportFatalError(
           "I can't create files for output. Memory may be exhausted." );*/

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

}

/*************************************************************************\
**
**  CreateAndOpenFile
**
**  Opens the output file stream pointed 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];

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

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

}

/*************************************************************************\
**
**  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 )
{
   tGridListIter<tSubNode> niter( g->GetNodeList() );
   tGridListIter<tEdge> eiter( g->GetEdgeList() );
   tListIter<tTriangle> titer( g->GetTriList() );
   tNode * cn;
   tEdge * ce;
   tTriangle * ct;
   int id;
   int nnodes = g->GetNodeList()->getSize();
   int nedges = g->GetEdgeList()->getSize();
   int ntri = g->GetTriList()->getSize();

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

   // 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 and z file
   nodeofs << " " << time << endl << nnodes << endl;
   zofs << " " << 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;
   }

   // 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;
   }

   WriteNodeData( time );

}

template< class tSubNode >
void tOutput<tSubNode>::WriteNodeData( double time )
{}

template< class tSubNode >
tLOutput<tSubNode>::tLOutput( tGrid<tSubNode> *g, tInputFile &infile )
        : tOutput<tSubNode>( g, infile )  // call base-class constructor
{
   //Xchar fullName[kMaxNameSize+6];

   /*Xstrcpy( fullName, baseName );
   strcat( fullName, ".area" );
   drareaofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".net" );
   netofs.open( fullName );

   if( !drareaofs.good() || !netofs.good() )
       ReportFatalError(
           "Unable to open output file. Storage space may be exhausted." );
           */

   CreateAndOpenFile( &drareaofs, ".area" );
   CreateAndOpenFile( &netofs, ".net" );
   CreateAndOpenFile( &slpofs, ".slp" );

}

template< class tSubNode >
void tLOutput<tSubNode>::WriteNodeData( double time )
{
   tGridListIter<tSubNode> ni( g->GetNodeList() );
   tSubNode *cn;
   int nActiveNodes = g->GetNodeList()->getActiveSize();

   drareaofs << " " << time << "\n " << nActiveNodes << endl;
   netofs << " " << time << "\n " << nActiveNodes << endl;
   slpofs << " " << time << "\n " << nActiveNodes << endl;
   for( cn = ni.FirstP(); ni.IsActive(); cn = ni.NextP() )
   {
      assert( cn>0 );
      drareaofs << cn->getDrArea() << endl;
      netofs << cn->GetDownstrmNbr()->getID() << endl;
      slpofs << cn->GetSlope() << endl;
   }

}
<commit_msg>added output of discharges to .q file<commit_after>/*************************************************************************\
**
**  tOutput.cpp: Functions for output objects
**
**
**
**  $Id: tOutput.cpp,v 1.5 1998-02-02 20:36:45 gtucker Exp $
\*************************************************************************/

#include "tOutput.h"

/*************************************************************************\
**
**  Constructor
**
**  The constructor takes two arguments, a pointer to the grid 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: gridPtr -- pointer to a tGrid object (or descendant), assumed
**                    valid
**         infile -- reference to an open input file, assumed valid
**
\*************************************************************************/
template< class tSubNode >
tOutput<tSubNode>::tOutput( tGrid<tSubNode> * gridPtr, tInputFile &infile )
{
   //Xchar fullName[kMaxNameSize+6];

   assert( gridPtr > 0 );
   g = gridPtr;

   infile.ReadItem( baseName, "OUTFILENAME" );
/*X   strcpy( fullName, baseName );
   strcat( fullName, ".nodes" );
   nodeofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".edges" );
   edgofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".tri" );
   triofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".z" );
   zofs.open( fullName );

   if( !nodeofs.good() || !edgofs.good() || !triofs.good() || !zofs.good() )
       ReportFatalError(
           "I can't create files for output. Memory may be exhausted." );*/

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

}

/*************************************************************************\
**
**  CreateAndOpenFile
**
**  Opens the output file stream pointed 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];

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

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

}

/*************************************************************************\
**
**  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 )
{
   tGridListIter<tSubNode> niter( g->GetNodeList() );
   tGridListIter<tEdge> eiter( g->GetEdgeList() );
   tListIter<tTriangle> titer( g->GetTriList() );
   tNode * cn;
   tEdge * ce;
   tTriangle * ct;
   int id;
   int nnodes = g->GetNodeList()->getSize();
   int nedges = g->GetEdgeList()->getSize();
   int ntri = g->GetTriList()->getSize();

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

   // 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 and z file
   nodeofs << " " << time << endl << nnodes << endl;
   zofs << " " << 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;
   }

   // 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;
   }

   WriteNodeData( time );

}

template< class tSubNode >
void tOutput<tSubNode>::WriteNodeData( double time )
{}

template< class tSubNode >
tLOutput<tSubNode>::tLOutput( tGrid<tSubNode> *g, tInputFile &infile )
        : tOutput<tSubNode>( g, infile )  // call base-class constructor
{
   //Xchar fullName[kMaxNameSize+6];

   /*Xstrcpy( fullName, baseName );
   strcat( fullName, ".area" );
   drareaofs.open( fullName );
   strcpy( fullName, baseName );
   strcat( fullName, ".net" );
   netofs.open( fullName );

   if( !drareaofs.good() || !netofs.good() )
       ReportFatalError(
           "Unable to open output file. Storage space may be exhausted." );
           */

   CreateAndOpenFile( &drareaofs, ".area" );
   CreateAndOpenFile( &netofs, ".net" );
   CreateAndOpenFile( &slpofs, ".slp" );
   CreateAndOpenFile( &qofs, ".q" );

}

template< class tSubNode >
void tLOutput<tSubNode>::WriteNodeData( double time )
{
   tGridListIter<tSubNode> ni( g->GetNodeList() );
   tSubNode *cn;
   int nActiveNodes = g->GetNodeList()->getActiveSize();

   drareaofs << " " << time << "\n " << nActiveNodes << endl;
   netofs << " " << time << "\n " << nActiveNodes << endl;
   slpofs << " " << time << "\n " << nActiveNodes << endl;
   qofs << " " << time << "\n " << nActiveNodes << endl;
   for( cn = ni.FirstP(); ni.IsActive(); cn = ni.NextP() )
   {
      assert( cn>0 );
      drareaofs << cn->getDrArea() << endl;
      netofs << cn->GetDownstrmNbr()->getID() << endl;
      slpofs << cn->GetSlope() << endl;
      qofs << cn->GetQ() << endl;
   }

}
<|endoftext|>


<commit_before>#ifndef __MALC_CUSTOM_TYPE_HPP__
#define __MALC_CUSTOM_TYPE_HPP__

#include <string>
#include <vector>
#include <type_traits>

#include <bl/base/platform.h>

#include <malcpp/malcpp.hpp>

// base resources to define custom log types. It won't work if you include
// malc_lean.hpp before.

namespace malcpp {
//------------------------------------------------------------------------------
template <uint8_t type_value>
struct builtin_map {
  static constexpr uint8_t value = type_value;
};
//------------------------------------------------------------------------------
template <class T>
struct builtin_type_map;

template<>
struct builtin_type_map<uint8_t>  : public builtin_map<malc_obj_u8> {};
template<>
struct builtin_type_map<int8_t>  : public builtin_map<malc_obj_i8> {};
template<>
struct builtin_type_map<uint16_t> : public builtin_map<malc_obj_u16> {};
template<>
struct builtin_type_map<int16_t> : public builtin_map<malc_obj_i16> {};
template<>
struct builtin_type_map<uint32_t> : public builtin_map<malc_obj_u32> {};
template<>
struct builtin_type_map<int32_t> : public builtin_map<malc_obj_i32> {};
template<>
struct builtin_type_map<uint64_t> : public builtin_map<malc_obj_u64> {};
template<>
struct builtin_type_map<int64_t> : public builtin_map<malc_obj_i64> {};
template<>
struct builtin_type_map<float> : public builtin_map<malc_obj_float> {};
template<>
struct builtin_type_map<double> : public builtin_map<malc_obj_double> {};
//------------------------------------------------------------------------------
struct MALC_EXPORT obj_log_data {
  //----------------------------------------------------------------------------
  static malc_obj_log_data get_as_str (char const* str, std::size_t len);
  //----------------------------------------------------------------------------
  template <int N>
  static inline malc_obj_log_data get (const char (&str)[N])
  {
    return obj_log_data::get_as_str (str, N - 1);
  }
  //----------------------------------------------------------------------------
  static inline malc_obj_log_data get (std::string const& s)
  {
    return obj_log_data::get_as_str (s.c_str(), s.size());
  }
  //----------------------------------------------------------------------------
  static inline malc_obj_log_data get_null_smartptr()
  {
    return obj_log_data::get (MALC_CPP_NULL_SMART_PTR_STR);
  }
  //----------------------------------------------------------------------------
  static malc_obj_log_data get(
    void const* addr, std::size_t count, uint8_t builtin_type
    );
  //----------------------------------------------------------------------------
  template <class T>
  static inline
  typename std::enable_if<
    detail::serialization::is_valid_builtin<T>::value,
    malc_obj_log_data
    >::type
  get (T const* first, std::size_t count)
  {
    return obj_log_data::get(
      (void*) &first[0], count, builtin_type_map<T>::value
      );
  }
  //----------------------------------------------------------------------------
  template <class T>
  static inline
  typename std::enable_if<
    detail::serialization::is_valid_builtin<T>::value,
    malc_obj_log_data
    >::type
  get (T& v)
  {
    return obj_log_data::get(
      (void*) &v, 1, builtin_type_map<T>::value
      );
  }
  //------------------------------------------------------------------------------
  template <class T>
  static inline malc_obj_log_data get (std::vector<T> const &v)
  {
    return obj_log_data::get (&v[0], v.size());
  }
  //------------------------------------------------------------------------------
};
//------------------------------------------------------------------------------
class log_entry_adder {
public:
  //----------------------------------------------------------------------------
  log_entry_adder (malc_obj_push_context const& pushcontext) : pc (pushcontext)
  {};
  //----------------------------------------------------------------------------
  int push (malc_obj_log_data const& ld) const noexcept
  {
    return malc_obj_push (&pc, &ld);
  }
  //----------------------------------------------------------------------------
  int push_as_str (char const* str, std::size_t len) const noexcept
  {
    return push (obj_log_data::get_as_str (str, len));
  }
  //----------------------------------------------------------------------------
  template <int N>
  int push (const char (&str)[N]) const noexcept
  {
    return push (obj_log_data::get_as_str (str, N - 1));
  }
  //----------------------------------------------------------------------------
  int push (std::string const& str) const noexcept
  {
    return push (obj_log_data::get (str));
  }
  //----------------------------------------------------------------------------
  int push_null_smartptr() const noexcept
  {
    return push (obj_log_data::get_null_smartptr ());
  }
  //----------------------------------------------------------------------------
  template <class T>
  int push (T const* first, std::size_t count) const noexcept
  {
    return push (obj_log_data::get (first, count));
  }
  //----------------------------------------------------------------------------
  template <class T>
  typename std::enable_if<
    detail::serialization::is_valid_builtin<T>::value,
    int
    >::type
  push (T v) const noexcept
  {
    return push (obj_log_data::get (v));
  }
  //----------------------------------------------------------------------------
  template <class T>
  int push (std::vector<T> const &v) const noexcept
  {
    return push (obj_log_data::get (v));
  }
  //----------------------------------------------------------------------------
private:
  //----------------------------------------------------------------------------
  malc_obj_push_context const& pc;
  //----------------------------------------------------------------------------
};
//------------------------------------------------------------------------------
template <class inherited>
class custom_log_type {
public:
  //----------------------------------------------------------------------------
  using type = inherited;
  //----------------------------------------------------------------------------
  static malc_obj_table const* get_table()
  {
    return &objtable;
  }
  //----------------------------------------------------------------------------
private:
  static const malc_obj_table objtable;
  //----------------------------------------------------------------------------
  static void destroy (malc_obj_ref* obj, void const*)
  {
    static_cast<inherited*> (obj->obj)->~inherited();
  }
  //----------------------------------------------------------------------------
  static int get_data(
    malc_obj_ref*                obj,
    void const*                  table,
    malc_obj_push_context const* pc,
    bl_alloc_tbl const*          alloc
    )
  {
    BL_TRY {
      return static_cast<inherited*> (obj->obj)->dump_value(
        log_entry_adder (*pc), obj->extra.context, obj->extra.flag, *alloc
        );
    }
    BL_CATCH (...) {
      return 1;
    }
  }
  //----------------------------------------------------------------------------
};
//------------------------------------------------------------------------------
template <class T>
const malc_obj_table custom_log_type<T>::objtable{
  get_data,
  destroy,
  sizeof (T)
};
//------------------------------------------------------------------------------
} // namespace malcpp

#endif // _MALCPP_CUSTOM_TYPE_
<commit_msg>custom_type: get: vector: avoid illegal access<commit_after>#ifndef __MALC_CUSTOM_TYPE_HPP__
#define __MALC_CUSTOM_TYPE_HPP__

#include <string>
#include <vector>
#include <type_traits>

#include <bl/base/platform.h>

#include <malcpp/malcpp.hpp>

// base resources to define custom log types. It won't work if you include
// malc_lean.hpp before.

namespace malcpp {
//------------------------------------------------------------------------------
template <uint8_t type_value>
struct builtin_map {
  static constexpr uint8_t value = type_value;
};
//------------------------------------------------------------------------------
template <class T>
struct builtin_type_map;

template<>
struct builtin_type_map<uint8_t>  : public builtin_map<malc_obj_u8> {};
template<>
struct builtin_type_map<int8_t>  : public builtin_map<malc_obj_i8> {};
template<>
struct builtin_type_map<uint16_t> : public builtin_map<malc_obj_u16> {};
template<>
struct builtin_type_map<int16_t> : public builtin_map<malc_obj_i16> {};
template<>
struct builtin_type_map<uint32_t> : public builtin_map<malc_obj_u32> {};
template<>
struct builtin_type_map<int32_t> : public builtin_map<malc_obj_i32> {};
template<>
struct builtin_type_map<uint64_t> : public builtin_map<malc_obj_u64> {};
template<>
struct builtin_type_map<int64_t> : public builtin_map<malc_obj_i64> {};
template<>
struct builtin_type_map<float> : public builtin_map<malc_obj_float> {};
template<>
struct builtin_type_map<double> : public builtin_map<malc_obj_double> {};
//------------------------------------------------------------------------------
struct MALC_EXPORT obj_log_data {
  //----------------------------------------------------------------------------
  static malc_obj_log_data get_as_str (char const* str, std::size_t len);
  //----------------------------------------------------------------------------
  template <int N>
  static inline malc_obj_log_data get (const char (&str)[N])
  {
    return obj_log_data::get_as_str (str, N - 1);
  }
  //----------------------------------------------------------------------------
  static inline malc_obj_log_data get (std::string const& s)
  {
    return obj_log_data::get_as_str (s.c_str(), s.size());
  }
  //----------------------------------------------------------------------------
  static inline malc_obj_log_data get_null_smartptr()
  {
    return obj_log_data::get (MALC_CPP_NULL_SMART_PTR_STR);
  }
  //----------------------------------------------------------------------------
  static malc_obj_log_data get(
    void const* addr, std::size_t count, uint8_t builtin_type
    );
  //----------------------------------------------------------------------------
  template <class T>
  static inline
  typename std::enable_if<
    detail::serialization::is_valid_builtin<T>::value,
    malc_obj_log_data
    >::type
  get (T const* first, std::size_t count)
  {
    return obj_log_data::get(
      (void*) &first[0], count, builtin_type_map<T>::value
      );
  }
  //----------------------------------------------------------------------------
  template <class T>
  static inline
  typename std::enable_if<
    detail::serialization::is_valid_builtin<T>::value,
    malc_obj_log_data
    >::type
  get (T& v)
  {
    return obj_log_data::get(
      (void*) &v, 1, builtin_type_map<T>::value
      );
  }
  //------------------------------------------------------------------------------
  template <class T>
  static inline malc_obj_log_data get (std::vector<T> const &v)
  {
    return obj_log_data::get (v.size() ? &v[0] : nullptr, v.size());
  }
  //------------------------------------------------------------------------------
};
//------------------------------------------------------------------------------
class log_entry_adder {
public:
  //----------------------------------------------------------------------------
  log_entry_adder (malc_obj_push_context const& pushcontext) : pc (pushcontext)
  {};
  //----------------------------------------------------------------------------
  int push (malc_obj_log_data const& ld) const noexcept
  {
    return malc_obj_push (&pc, &ld);
  }
  //----------------------------------------------------------------------------
  int push_as_str (char const* str, std::size_t len) const noexcept
  {
    return push (obj_log_data::get_as_str (str, len));
  }
  //----------------------------------------------------------------------------
  template <int N>
  int push (const char (&str)[N]) const noexcept
  {
    return push (obj_log_data::get_as_str (str, N - 1));
  }
  //----------------------------------------------------------------------------
  int push (std::string const& str) const noexcept
  {
    return push (obj_log_data::get (str));
  }
  //----------------------------------------------------------------------------
  int push_null_smartptr() const noexcept
  {
    return push (obj_log_data::get_null_smartptr ());
  }
  //----------------------------------------------------------------------------
  template <class T>
  int push (T const* first, std::size_t count) const noexcept
  {
    return push (obj_log_data::get (first, count));
  }
  //----------------------------------------------------------------------------
  template <class T>
  typename std::enable_if<
    detail::serialization::is_valid_builtin<T>::value,
    int
    >::type
  push (T v) const noexcept
  {
    return push (obj_log_data::get (v));
  }
  //----------------------------------------------------------------------------
  template <class T>
  int push (std::vector<T> const &v) const noexcept
  {
    return push (obj_log_data::get (v));
  }
  //----------------------------------------------------------------------------
private:
  //----------------------------------------------------------------------------
  malc_obj_push_context const& pc;
  //----------------------------------------------------------------------------
};
//------------------------------------------------------------------------------
template <class inherited>
class custom_log_type {
public:
  //----------------------------------------------------------------------------
  using type = inherited;
  //----------------------------------------------------------------------------
  static malc_obj_table const* get_table()
  {
    return &objtable;
  }
  //----------------------------------------------------------------------------
private:
  static const malc_obj_table objtable;
  //----------------------------------------------------------------------------
  static void destroy (malc_obj_ref* obj, void const*)
  {
    static_cast<inherited*> (obj->obj)->~inherited();
  }
  //----------------------------------------------------------------------------
  static int get_data(
    malc_obj_ref*                obj,
    void const*                  table,
    malc_obj_push_context const* pc,
    bl_alloc_tbl const*          alloc
    )
  {
    BL_TRY {
      return static_cast<inherited*> (obj->obj)->dump_value(
        log_entry_adder (*pc), obj->extra.context, obj->extra.flag, *alloc
        );
    }
    BL_CATCH (...) {
      return 1;
    }
  }
  //----------------------------------------------------------------------------
};
//------------------------------------------------------------------------------
template <class T>
const malc_obj_table custom_log_type<T>::objtable{
  get_data,
  destroy,
  sizeof (T)
};
//------------------------------------------------------------------------------
} // namespace malcpp

#endif // _MALCPP_CUSTOM_TYPE_
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "fileinprojectfinder.h"
#include <utils/qtcassert.h>

#include <QtCore/QFileInfo>
#include <QtCore/QUrl>

namespace Utils {

/*!
  \class Utils::FileInProjectFinder

  \brief Helper class to find the 'original' file in the project directory for a given file url.

  Often files are copied in the build + deploy process. findFile() searches for an existing file
  in the project directory for a given file path:

  E.g. following file paths:
  \list
  \i C:/app-build-desktop/qml/app/main.qml (shadow build directory)
  \i C:/Private/e3026d63/qml/app/main.qml  (Application data folder on Symbian device)
  \i /Users/x/app-build-desktop/App.app/Contents/Resources/qml/App/main.qml (folder on Mac OS X)
  \endlist

 should all be mapped to $PROJECTDIR/qml/app/main.qml
*/

FileInProjectFinder::FileInProjectFinder()
{
}

static QString stripTrailingSlashes(const QString &path)
{
    QString newPath = path;
    while (newPath.endsWith(QLatin1Char('/')))
        newPath.remove(newPath.length() - 1, 1);
    return newPath;
}

void FileInProjectFinder::setProjectDirectory(const QString &absoluteProjectPath)
{
    const QString newProjectPath = stripTrailingSlashes(absoluteProjectPath);

    if (newProjectPath == m_projectDir)
        return;

    const QFileInfo infoPath(newProjectPath);
    QTC_CHECK(newProjectPath.isEmpty()
              || (infoPath.exists() && infoPath.isAbsolute()));

    m_projectDir = newProjectPath;
    m_cache.clear();
}

QString FileInProjectFinder::projectDirectory() const
{
    return m_projectDir;
}

void FileInProjectFinder::setProjectFiles(const QStringList &projectFiles)
{
    if (m_projectFiles == projectFiles)
        return;

    m_projectFiles = projectFiles;
    m_cache.clear();
}

void FileInProjectFinder::setSysroot(const QString &sysroot)
{
    QString newsys = sysroot;
    while (newsys.endsWith(QLatin1Char('/')))
        newsys.remove(newsys.length() - 1, 1);

    if (m_sysroot == newsys)
        return;

    m_sysroot = newsys;
    m_cache.clear();
}

/**
  Returns the best match for the given file url in the project directory.

  The method first checks whether the file inside the project directory exists.
  If not, the leading directory in the path is stripped, and the - now shorter - path is
  checked for existence, and so on. Second, it tries to locate the file in the sysroot
  folder specified. Third, we walk the list of project files, and search for a file name match
  there. If all fails, it returns the original path from the file url.
  */
QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
{
    QString originalPath = fileUrl.toLocalFile();
    if (originalPath.isEmpty()) // e.g. qrc://
        originalPath = fileUrl.path();

    if (originalPath.isEmpty()) {
        if (success)
            *success = false;
        return originalPath;
    }

    if (!m_projectDir.isEmpty()) {
        int prefixToIgnore = -1;
        const QChar separator = QLatin1Char('/');
        if (originalPath.startsWith(m_projectDir + separator)) {
#ifdef Q_OS_MAC
            // starting with the project path is not sufficient if the file was
            // copied in an insource build, e.g. into MyApp.app/Contents/Resources
            static const QString appResourcePath = QString::fromLatin1(".app/Contents/Resources");
            if (originalPath.contains(appResourcePath)) {
                // the path is inside the project, but most probably as a resource of an insource build
                // so ignore that path
                prefixToIgnore = originalPath.indexOf(appResourcePath) + appResourcePath.length();
            } else {
#endif
                if (success)
                    *success = true;
                return originalPath;
#ifdef Q_OS_MAC
            }
#endif
        }

        if (m_cache.contains(originalPath)) {
            // check if cached path is still there
            QString candidate = m_cache.value(originalPath);
            QFileInfo candidateInfo(candidate);
            if (candidateInfo.exists() && candidateInfo.isFile()) {
                if (success)
                    *success = true;
                return candidate;
            }
        }

        // Strip directories one by one from the beginning of the path,
        // and see if the new relative path exists in the build directory.
        if (prefixToIgnore < 0) {
            if (!QFileInfo(originalPath).isAbsolute()
                    && !originalPath.startsWith(separator)) {
                prefixToIgnore = 0;
            } else {
                prefixToIgnore = originalPath.indexOf(separator);
            }
        }
        while (prefixToIgnore != -1) {
            QString candidate = originalPath;
            candidate.remove(0, prefixToIgnore);
            candidate.prepend(m_projectDir);
            QFileInfo candidateInfo(candidate);
            if (candidateInfo.exists() && candidateInfo.isFile()) {
                if (success)
                    *success = true;

                m_cache.insert(originalPath, candidate);
                return candidate;
            }
            prefixToIgnore = originalPath.indexOf(separator, prefixToIgnore + 1);
        }
    }

    // check if absolute path is found in sysroot
    if (!m_sysroot.isEmpty()) {
        const QString sysrootPath = m_sysroot + QLatin1Char('/') + originalPath;
        if (QFileInfo(sysrootPath).exists() && QFileInfo(sysrootPath).isFile()) {
            if (success)
                *success = true;
            m_cache.insert(originalPath, sysrootPath);
            return sysrootPath;
        }
    }

    // finally, find solely by filename in project files
    const QString fileName = QFileInfo(originalPath).fileName();
    foreach (const QString &f, m_projectFiles) {
        if (QFileInfo(f).fileName() == fileName) {
            m_cache.insert(originalPath, f);
            if (success)
                *success = true;
            return f;
        }
    }

    if (success)
        *success = false;

    return originalPath;
}

} // namespace Utils
<commit_msg>FileInProjectFinder: Avoid double slash in sysroot'ed path<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "fileinprojectfinder.h"
#include <utils/qtcassert.h>

#include <QtCore/QFileInfo>
#include <QtCore/QUrl>

namespace Utils {

/*!
  \class Utils::FileInProjectFinder

  \brief Helper class to find the 'original' file in the project directory for a given file url.

  Often files are copied in the build + deploy process. findFile() searches for an existing file
  in the project directory for a given file path:

  E.g. following file paths:
  \list
  \i C:/app-build-desktop/qml/app/main.qml (shadow build directory)
  \i C:/Private/e3026d63/qml/app/main.qml  (Application data folder on Symbian device)
  \i /Users/x/app-build-desktop/App.app/Contents/Resources/qml/App/main.qml (folder on Mac OS X)
  \endlist

 should all be mapped to $PROJECTDIR/qml/app/main.qml
*/

FileInProjectFinder::FileInProjectFinder()
{
}

static QString stripTrailingSlashes(const QString &path)
{
    QString newPath = path;
    while (newPath.endsWith(QLatin1Char('/')))
        newPath.remove(newPath.length() - 1, 1);
    return newPath;
}

void FileInProjectFinder::setProjectDirectory(const QString &absoluteProjectPath)
{
    const QString newProjectPath = stripTrailingSlashes(absoluteProjectPath);

    if (newProjectPath == m_projectDir)
        return;

    const QFileInfo infoPath(newProjectPath);
    QTC_CHECK(newProjectPath.isEmpty()
              || (infoPath.exists() && infoPath.isAbsolute()));

    m_projectDir = newProjectPath;
    m_cache.clear();
}

QString FileInProjectFinder::projectDirectory() const
{
    return m_projectDir;
}

void FileInProjectFinder::setProjectFiles(const QStringList &projectFiles)
{
    if (m_projectFiles == projectFiles)
        return;

    m_projectFiles = projectFiles;
    m_cache.clear();
}

void FileInProjectFinder::setSysroot(const QString &sysroot)
{
    QString newsys = sysroot;
    while (newsys.endsWith(QLatin1Char('/')))
        newsys.remove(newsys.length() - 1, 1);

    if (m_sysroot == newsys)
        return;

    m_sysroot = newsys;
    m_cache.clear();
}

/**
  Returns the best match for the given file url in the project directory.

  The method first checks whether the file inside the project directory exists.
  If not, the leading directory in the path is stripped, and the - now shorter - path is
  checked for existence, and so on. Second, it tries to locate the file in the sysroot
  folder specified. Third, we walk the list of project files, and search for a file name match
  there. If all fails, it returns the original path from the file url.
  */
QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
{
    QString originalPath = fileUrl.toLocalFile();
    if (originalPath.isEmpty()) // e.g. qrc://
        originalPath = fileUrl.path();

    if (originalPath.isEmpty()) {
        if (success)
            *success = false;
        return originalPath;
    }

    if (!m_projectDir.isEmpty()) {
        int prefixToIgnore = -1;
        const QChar separator = QLatin1Char('/');
        if (originalPath.startsWith(m_projectDir + separator)) {
#ifdef Q_OS_MAC
            // starting with the project path is not sufficient if the file was
            // copied in an insource build, e.g. into MyApp.app/Contents/Resources
            static const QString appResourcePath = QString::fromLatin1(".app/Contents/Resources");
            if (originalPath.contains(appResourcePath)) {
                // the path is inside the project, but most probably as a resource of an insource build
                // so ignore that path
                prefixToIgnore = originalPath.indexOf(appResourcePath) + appResourcePath.length();
            } else {
#endif
                if (success)
                    *success = true;
                return originalPath;
#ifdef Q_OS_MAC
            }
#endif
        }

        if (m_cache.contains(originalPath)) {
            // check if cached path is still there
            QString candidate = m_cache.value(originalPath);
            QFileInfo candidateInfo(candidate);
            if (candidateInfo.exists() && candidateInfo.isFile()) {
                if (success)
                    *success = true;
                return candidate;
            }
        }

        // Strip directories one by one from the beginning of the path,
        // and see if the new relative path exists in the build directory.
        if (prefixToIgnore < 0) {
            if (!QFileInfo(originalPath).isAbsolute()
                    && !originalPath.startsWith(separator)) {
                prefixToIgnore = 0;
            } else {
                prefixToIgnore = originalPath.indexOf(separator);
            }
        }
        while (prefixToIgnore != -1) {
            QString candidate = originalPath;
            candidate.remove(0, prefixToIgnore);
            candidate.prepend(m_projectDir);
            QFileInfo candidateInfo(candidate);
            if (candidateInfo.exists() && candidateInfo.isFile()) {
                if (success)
                    *success = true;

                m_cache.insert(originalPath, candidate);
                return candidate;
            }
            prefixToIgnore = originalPath.indexOf(separator, prefixToIgnore + 1);
        }
    }

    // check if absolute path is found in sysroot
    if (!m_sysroot.isEmpty()) {
        const QString sysrootPath = m_sysroot + originalPath;
        if (QFileInfo(sysrootPath).exists() && QFileInfo(sysrootPath).isFile()) {
            if (success)
                *success = true;
            m_cache.insert(originalPath, sysrootPath);
            return sysrootPath;
        }
    }

    // finally, find solely by filename in project files
    const QString fileName = QFileInfo(originalPath).fileName();
    foreach (const QString &f, m_projectFiles) {
        if (QFileInfo(f).fileName() == fileName) {
            m_cache.insert(originalPath, f);
            if (success)
                *success = true;
            return f;
        }
    }

    if (success)
        *success = false;

    return originalPath;
}

} // namespace Utils
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <map>
#include <qi/atomic.hpp>

#include <boost/thread/recursive_mutex.hpp>

#include <qitype/signal.hpp>
#include <qitype/genericvalue.hpp>
#include <qitype/genericobject.hpp>

#include "object_p.hpp"
#include "signal_p.hpp"

namespace qi {

  SignalSubscriber::SignalSubscriber(qi::ObjectPtr target, unsigned int method)
  : weakLock(0), target(new qi::ObjectWeakPtr(target)), method(method), enabled(true), active(0)
  {}

  SignalSubscriber::SignalSubscriber(GenericFunction func, EventLoop* ctx, detail::WeakLock* lock)
     : handler(func), weakLock(lock), target(0), method(0), enabled(true), active(0)
   {
     eventLoopGetter = boost::bind(detail::eventLoopGet, ctx);
   }

  SignalSubscriber::~SignalSubscriber()
  {
    delete target;
    delete weakLock;
  }

  SignalSubscriber::SignalSubscriber(const SignalSubscriber& b)
  : weakLock(0), target(0)
  {
    *this = b;
  }

  void SignalSubscriber::operator=(const SignalSubscriber& b)
  {
    source = b.source;
    linkId = b.linkId;
    handler = b.handler;
    weakLock = b.weakLock?b.weakLock->clone():0;
    eventLoopGetter = b.eventLoopGetter;
    target = b.target?new ObjectWeakPtr(*b.target):0;
    method = b.method;
    enabled = b.enabled;
    active = 0;
  }

  static qi::atomic<long> linkUid = 1;

  void SignalBase::operator()(
      qi::AutoGenericValue p1,
      qi::AutoGenericValue p2,
      qi::AutoGenericValue p3,
      qi::AutoGenericValue p4,
      qi::AutoGenericValue p5,
      qi::AutoGenericValue p6,
      qi::AutoGenericValue p7,
      qi::AutoGenericValue p8)
  {
    qi::AutoGenericValue* vals[8]= {&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8};
    std::vector<qi::GenericValue> params;
    for (unsigned i=0; i<8; ++i)
      if (vals[i]->value)
        params.push_back(*vals[i]);
    // Signature construction
    std::string signature = "(";
    for (unsigned i=0; i< params.size(); ++i)
      signature += params[i].signature();
    signature += ")";
    if (signature != _p->signature)
    {
      qiLogError("qi.signal") << "Dropping emit: signature mismatch: " << signature <<" " << _p->signature;
      return;
    }
    trigger(params);
  }

  void SignalBase::trigger(const GenericFunctionParameters& params)
  {
    if (!_p)
      return;
    SignalSubscriberMap copy;
    {
      boost::recursive_mutex::scoped_lock sl(_p->mutex);
      copy = _p->subscriberMap;
    }
    SignalSubscriberMap::iterator i;
    for (i=copy.begin(); i!= copy.end(); ++i)
    {
      i->second->call(params);
    }
  }

  class FunctorCall
  {
  public:
    FunctorCall(GenericFunctionParameters& params,
      SignalSubscriber* sub)
    : sub(sub)
    {
      std::swap((std::vector<GenericValue>&)this->params, (std::vector<GenericValue>&)params);
    }
    FunctorCall(const FunctorCall& b)
    {
      *this = b;
    }
    void operator=(const FunctorCall& b)
    {
      std::swap((std::vector<GenericValue>&)(this->params),
        (std::vector<GenericValue>&)b.params);
      sub = b.sub;
    }
    GenericFunctionParameters params;
    SignalSubscriber* sub;
    void operator() ()
    {
      if (sub->enabled)
        sub->handler(params);
      long active = --sub->active;
      params.destroy();
      if (sub->weakLock && !active)
        sub->weakLock->unlock();
    }
  };
  void SignalSubscriber::call(const GenericFunctionParameters& args)
  {
    if (!enabled)
      return;
    if (handler.type)
    {
      if (weakLock)
      {
        bool locked = weakLock->tryLock();
        if (!locked)
        {
          source->disconnect(linkId);
          return;
        }
      }
      EventLoop* eventLoop = 0;
      if (eventLoopGetter)
        eventLoop = eventLoopGetter();
      if (eventLoop)
      {
        ++active;
        // Event emission is always asynchronous
        GenericFunctionParameters copy = args.copy();
        eventLoop->asyncCall(0, FunctorCall(copy, this));
      }
      else
      {
        handler(args);
        if (weakLock)
          weakLock->unlock();
      }
    }
    else if (target)
    {
      ObjectPtr lockedTarget = target->lock();
      if (!lockedTarget)
        source->disconnect(linkId);
      else
        lockedTarget->metaEmit(method, args);
    }
  }

  SignalBase::Link SignalBase::connect(GenericFunction callback, EventLoop* ctx)
  {
    return connect(SignalSubscriber(callback, ctx));
  }

  SignalBase::Link SignalBase::connect(qi::ObjectPtr o, unsigned int slot)
  {
    return connect(SignalSubscriber(o, slot));
  }

  SignalBase::Link SignalBase::connect(const SignalSubscriber& src)
  {
    if (!_p)
    {
      _p = boost::shared_ptr<SignalBasePrivate>(new SignalBasePrivate());
    }
    // Check arity. Does not require to acquire weakLock.
    int sigArity = Signature(signature()).begin().children().size();
    int subArity = -1;
    if (src.handler.type)
    {
      if (src.handler.type == dynamicFunctionType())
        goto proceed; // no arity checking is possible
      subArity = src.handler.type->argumentsType().size();
    }
    else if (src.target)
    {
      ObjectPtr locked = src.target->lock();
      if (!locked)
      {
        qiLogVerbose("qi.signal") << "connecting a dead slot (weak ptr out)";
        return SignalBase::invalidLink;
      }
      const MetaMethod* ms = locked->metaObject().method(src.method);
      if (!ms)
      {
        qiLogWarning("qi.signal") << "Method " << src.method <<" not found, proceeding anyway";
        goto proceed;
      }
      else
        subArity = Signature(qi::signatureSplit(ms->signature())[2]).size();
    }
    if (sigArity != subArity)
    {
      qiLogWarning("qi.signal") << "Subscriber has incorrect arity (expected "
        << sigArity  << " , got " << subArity <<")";
      return SignalBase::invalidLink;
    }
  proceed:
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    Link res = ++linkUid;
    _p->subscriberMap[res] = new SignalSubscriber(src);
    SignalSubscriber& s = *_p->subscriberMap[res];
    s.linkId = res;
    s.source = this;
    return res;
  }

  bool SignalBase::disconnectAll() {
    if (_p)
      return _p->reset();
    return false;
  }

  SignalBase::SignalBase(const std::string& sig)
    : _p(new SignalBasePrivate)
  {
    _p->signature = sig;
  }

  SignalBase::SignalBase()
  {
  }

  SignalBase::SignalBase(const SignalBase& b)
  {
    (*this) = b;
  }

  SignalBase& SignalBase::operator=(const SignalBase& b)
  {
    if (!b._p)
    {
      const_cast<SignalBase&>(b)._p = boost::shared_ptr<SignalBasePrivate>(new SignalBasePrivate());
    }
    _p = b._p;
    return *this;
  }

  std::string SignalBase::signature() const
  {
    return _p?_p->signature:"";
  }

  bool SignalBasePrivate::disconnect(const SignalBase::Link& l)
  {
    boost::recursive_mutex::scoped_lock sl(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.find(l);
    if (it == subscriberMap.end())
      return false;
    SignalSubscriber* s = it->second;
    // Ensure no call on subscriber occurrs once this function returns
    s->enabled = false;
    while (*(s->active))
      os::msleep(1); // FIXME too long
    subscriberMap.erase(it);
    delete s;
    return true;
  }

  bool SignalBase::disconnect(const Link &link) {
    if (!_p)
      return false;
    else
      return _p->disconnect(link);
  }

  SignalBase::~SignalBase()
  {
    if (!_p)
      return;
    SignalSubscriberMap::iterator i;
    std::vector<Link> links;
    for (i = _p->subscriberMap.begin(); i!= _p->subscriberMap.end(); ++i)
    {
      links.push_back(i->first);
    }
    for (unsigned i=0; i<links.size(); ++i)
      disconnect(links[i]);
  }

  std::vector<SignalSubscriber> SignalBase::subscribers()
  {
    std::vector<SignalSubscriber> res;
    if (!_p)
      return res;
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    SignalSubscriberMap::iterator i;
    for (i = _p->subscriberMap.begin(); i!= _p->subscriberMap.end(); ++i)
      res.push_back(*i->second);
    return res;
  }

  bool SignalBasePrivate::reset() {
    bool ret = true;
    boost::recursive_mutex::scoped_lock sl(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.begin();
    while (it != subscriberMap.end()) {
      bool b = disconnect(it->first);
      if (!b)
        ret = false;
      it = subscriberMap.begin();
    }
    return ret;
  }

  QITYPE_API const SignalBase::Link SignalBase::invalidLink = ((unsigned int)-1);

}
<commit_msg>Signal: Reduce trigger window of a race condition.<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <map>
#include <qi/atomic.hpp>

#include <boost/thread/recursive_mutex.hpp>

#include <qitype/signal.hpp>
#include <qitype/genericvalue.hpp>
#include <qitype/genericobject.hpp>

#include "object_p.hpp"
#include "signal_p.hpp"

namespace qi {

  SignalSubscriber::SignalSubscriber(qi::ObjectPtr target, unsigned int method)
  : weakLock(0), target(new qi::ObjectWeakPtr(target)), method(method), enabled(true), active(0)
  {}

  SignalSubscriber::SignalSubscriber(GenericFunction func, EventLoop* ctx, detail::WeakLock* lock)
     : handler(func), weakLock(lock), target(0), method(0), enabled(true), active(0)
   {
     eventLoopGetter = boost::bind(detail::eventLoopGet, ctx);
   }

  SignalSubscriber::~SignalSubscriber()
  {
    delete target;
    delete weakLock;
  }

  SignalSubscriber::SignalSubscriber(const SignalSubscriber& b)
  : weakLock(0), target(0)
  {
    *this = b;
  }

  void SignalSubscriber::operator=(const SignalSubscriber& b)
  {
    source = b.source;
    linkId = b.linkId;
    handler = b.handler;
    weakLock = b.weakLock?b.weakLock->clone():0;
    eventLoopGetter = b.eventLoopGetter;
    target = b.target?new ObjectWeakPtr(*b.target):0;
    method = b.method;
    enabled = b.enabled;
    active = 0;
  }

  static qi::atomic<long> linkUid = 1;

  void SignalBase::operator()(
      qi::AutoGenericValue p1,
      qi::AutoGenericValue p2,
      qi::AutoGenericValue p3,
      qi::AutoGenericValue p4,
      qi::AutoGenericValue p5,
      qi::AutoGenericValue p6,
      qi::AutoGenericValue p7,
      qi::AutoGenericValue p8)
  {
    qi::AutoGenericValue* vals[8]= {&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8};
    std::vector<qi::GenericValue> params;
    for (unsigned i=0; i<8; ++i)
      if (vals[i]->value)
        params.push_back(*vals[i]);
    // Signature construction
    std::string signature = "(";
    for (unsigned i=0; i< params.size(); ++i)
      signature += params[i].signature();
    signature += ")";
    if (signature != _p->signature)
    {
      qiLogError("qi.signal") << "Dropping emit: signature mismatch: " << signature <<" " << _p->signature;
      return;
    }
    trigger(params);
  }

  void SignalBase::trigger(const GenericFunctionParameters& params)
  {
    if (!_p)
      return;
    SignalSubscriberMap copy;
    {
      boost::recursive_mutex::scoped_lock sl(_p->mutex);
      copy = _p->subscriberMap;
    }
    SignalSubscriberMap::iterator i;
    for (i=copy.begin(); i!= copy.end(); ++i)
    {
      i->second->call(params);
    }
  }

  class FunctorCall
  {
  public:
    FunctorCall(GenericFunctionParameters& params,
      SignalSubscriber* sub)
    : sub(sub)
    {
      std::swap((std::vector<GenericValue>&)this->params, (std::vector<GenericValue>&)params);
    }
    FunctorCall(const FunctorCall& b)
    {
      *this = b;
    }
    void operator=(const FunctorCall& b)
    {
      std::swap((std::vector<GenericValue>&)(this->params),
        (std::vector<GenericValue>&)b.params);
      sub = b.sub;
    }
    GenericFunctionParameters params;
    SignalSubscriber* sub;
    void operator() ()
    {
      if (sub->enabled)
        sub->handler(params);
      params.destroy();
      long active = --sub->active;
      if (sub->weakLock && !active)
        sub->weakLock->unlock();
    }
  };
  void SignalSubscriber::call(const GenericFunctionParameters& args)
  {
    if (!enabled)
      return;
    if (handler.type)
    {
      if (weakLock)
      {
        bool locked = weakLock->tryLock();
        if (!locked)
        {
          source->disconnect(linkId);
          return;
        }
      }
      EventLoop* eventLoop = 0;
      if (eventLoopGetter)
        eventLoop = eventLoopGetter();
      if (eventLoop)
      {
        ++active;
        // Event emission is always asynchronous
        GenericFunctionParameters copy = args.copy();
        eventLoop->asyncCall(0, FunctorCall(copy, this));
      }
      else
      {
        handler(args);
        if (weakLock)
          weakLock->unlock();
      }
    }
    else if (target)
    {
      ObjectPtr lockedTarget = target->lock();
      if (!lockedTarget)
        source->disconnect(linkId);
      else
        lockedTarget->metaEmit(method, args);
    }
  }

  SignalBase::Link SignalBase::connect(GenericFunction callback, EventLoop* ctx)
  {
    return connect(SignalSubscriber(callback, ctx));
  }

  SignalBase::Link SignalBase::connect(qi::ObjectPtr o, unsigned int slot)
  {
    return connect(SignalSubscriber(o, slot));
  }

  SignalBase::Link SignalBase::connect(const SignalSubscriber& src)
  {
    if (!_p)
    {
      _p = boost::shared_ptr<SignalBasePrivate>(new SignalBasePrivate());
    }
    // Check arity. Does not require to acquire weakLock.
    int sigArity = Signature(signature()).begin().children().size();
    int subArity = -1;
    if (src.handler.type)
    {
      if (src.handler.type == dynamicFunctionType())
        goto proceed; // no arity checking is possible
      subArity = src.handler.type->argumentsType().size();
    }
    else if (src.target)
    {
      ObjectPtr locked = src.target->lock();
      if (!locked)
      {
        qiLogVerbose("qi.signal") << "connecting a dead slot (weak ptr out)";
        return SignalBase::invalidLink;
      }
      const MetaMethod* ms = locked->metaObject().method(src.method);
      if (!ms)
      {
        qiLogWarning("qi.signal") << "Method " << src.method <<" not found, proceeding anyway";
        goto proceed;
      }
      else
        subArity = Signature(qi::signatureSplit(ms->signature())[2]).size();
    }
    if (sigArity != subArity)
    {
      qiLogWarning("qi.signal") << "Subscriber has incorrect arity (expected "
        << sigArity  << " , got " << subArity <<")";
      return SignalBase::invalidLink;
    }
  proceed:
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    Link res = ++linkUid;
    _p->subscriberMap[res] = new SignalSubscriber(src);
    SignalSubscriber& s = *_p->subscriberMap[res];
    s.linkId = res;
    s.source = this;
    return res;
  }

  bool SignalBase::disconnectAll() {
    if (_p)
      return _p->reset();
    return false;
  }

  SignalBase::SignalBase(const std::string& sig)
    : _p(new SignalBasePrivate)
  {
    _p->signature = sig;
  }

  SignalBase::SignalBase()
  {
  }

  SignalBase::SignalBase(const SignalBase& b)
  {
    (*this) = b;
  }

  SignalBase& SignalBase::operator=(const SignalBase& b)
  {
    if (!b._p)
    {
      const_cast<SignalBase&>(b)._p = boost::shared_ptr<SignalBasePrivate>(new SignalBasePrivate());
    }
    _p = b._p;
    return *this;
  }

  std::string SignalBase::signature() const
  {
    return _p?_p->signature:"";
  }

  bool SignalBasePrivate::disconnect(const SignalBase::Link& l)
  {
    boost::recursive_mutex::scoped_lock sl(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.find(l);
    if (it == subscriberMap.end())
      return false;
    SignalSubscriber* s = it->second;
    // Ensure no call on subscriber occurrs once this function returns
    s->enabled = false;
    while (*(s->active))
      os::msleep(1); // FIXME too long
    subscriberMap.erase(it);
    delete s;
    return true;
  }

  bool SignalBase::disconnect(const Link &link) {
    if (!_p)
      return false;
    else
      return _p->disconnect(link);
  }

  SignalBase::~SignalBase()
  {
    if (!_p)
      return;
    SignalSubscriberMap::iterator i;
    std::vector<Link> links;
    for (i = _p->subscriberMap.begin(); i!= _p->subscriberMap.end(); ++i)
    {
      links.push_back(i->first);
    }
    for (unsigned i=0; i<links.size(); ++i)
      disconnect(links[i]);
  }

  std::vector<SignalSubscriber> SignalBase::subscribers()
  {
    std::vector<SignalSubscriber> res;
    if (!_p)
      return res;
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    SignalSubscriberMap::iterator i;
    for (i = _p->subscriberMap.begin(); i!= _p->subscriberMap.end(); ++i)
      res.push_back(*i->second);
    return res;
  }

  bool SignalBasePrivate::reset() {
    bool ret = true;
    boost::recursive_mutex::scoped_lock sl(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.begin();
    while (it != subscriberMap.end()) {
      bool b = disconnect(it->first);
      if (!b)
        ret = false;
      it = subscriberMap.begin();
    }
    return ret;
  }

  QITYPE_API const SignalBase::Link SignalBase::invalidLink = ((unsigned int)-1);

}
<|endoftext|>


<commit_before>#pragma once

/*
MIT License
Copyright (c) 2017 Arlen Keshabyan (arlen.albert@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace nstd
{

template <typename ValueType>
class topological_sorter
{
public:
    using value_type = ValueType;

protected:
	struct relations
	{
		std::size_t dependencies { 0 };
		std::unordered_set<value_type> dependents {};
	};

	std::unordered_map<value_type, relations> _map {};

public:
	void add(const value_type &object)
	{
		_map.try_emplace(object, relations {});
	}

	void add(const value_type &object, const value_type &dependency)
	{
		if (dependency == object) return;

		auto &dependents = _map[dependency].dependents;

		if (dependents.find(object) == dependents.end())
		{
			dependents.insert(object);

			++_map[object].dependencies;
		}
	}

	template <typename Container>
	void add(const value_type &object, const Container &dependencies)
	{
	    static_assert(std::is_same<value_type, typename std::decay<typename Container::value_type>::type>::value, "The Container's value_type and object's type must be the same!");

		for (auto const &dependency : dependencies) add(object, dependency);
	}

	void add(const value_type &object, const std::initializer_list<value_type> &dependencies)
	{
		add<std::initializer_list<value_type>>(object, dependencies);
	}

	auto sort()
	{
	    std::vector<value_type> sorted, cycled;
	    auto map { _map };

		for(const auto &[object, relations] : map) if (!relations.dependencies) sorted.push_back(object);

		for(decltype(std::size(sorted)) idx = 0; idx < std::size(sorted); ++idx)
			for(auto const& object : map[sorted[idx]].dependents)
                if (!--map[object].dependencies) sorted.push_back(object);

		for(const auto &[object, relations] : map) if(relations.dependencies) cycled.push_back(std::move(object));

		return std::pair(std::move(sorted), std::move(cycled));
	}

	void clear()
	{
		_map.clear();
	}
};

}
<commit_msg>small changes<commit_after>#pragma once

/*
MIT License
Copyright (c) 2017 Arlen Keshabyan (arlen.albert@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace nstd
{

template <typename ValueType>
class topological_sorter
{
public:
    using value_type = ValueType;

protected:
	struct relations
	{
		std::size_t dependencies { 0 };
		std::unordered_set<value_type> dependents {};
	};

	std::unordered_map<value_type, relations> _map {};

public:
	void add(const value_type &object)
	{
		_map.try_emplace(object, relations {});
	}

	void add(const value_type &object, const value_type &dependency)
	{
		if (dependency == object) return;

		auto &dependents = _map[dependency].dependents;

		if (dependents.find(object) == dependents.end())
		{
			dependents.insert(object);

			++_map[object].dependencies;
		}
	}

	template <typename Container>
	void add(const value_type &object, const Container &dependencies)
	{
		for (auto const &dependency : dependencies) add(object, dependency);
	}

	void add(const value_type &object, const std::initializer_list<value_type> &dependencies)
	{
		add<std::initializer_list<value_type>>(object, dependencies);
	}

	auto sort()
	{
	    std::vector<value_type> sorted, cycled;
	    auto map { _map };

		for(const auto &[object, relations] : map) if (!relations.dependencies) sorted.push_back(object);

		for(decltype(std::size(sorted)) idx = 0; idx < std::size(sorted); ++idx)
			for(auto const& object : map[sorted[idx]].dependents)
                if (!--map[object].dependencies) sorted.push_back(object);

		for(const auto &[object, relations] : map) if(relations.dependencies) cycled.push_back(std::move(object));

		return std::pair(std::move(sorted), std::move(cycled));
	}

	void clear()
	{
		_map.clear();
	}
};

}
<|endoftext|>


<commit_before>#ifndef VSMC_CORE_PARTICLE_HPP
#define VSMC_CORE_PARTICLE_HPP

#include <vsmc/internal/common.hpp>
#include <vsmc/internal/resampling.hpp>

namespace vsmc {

/// \brief Particle class representing the whole particle set
/// \ingroup Core
///
/// \tparam T Requirement:
/// \li Constructor compatible with
/// \code T(Particle<T>::size_type N) \endcode
/// \li member function copy method compatible with
/// \code copy(Particle<T>::size_type from, Particle<T>::size_type to) \endcode
template <typename T>
class Particle
{
    public :

    /// The type of the number of particles
    typedef VSMC_SIZE_TYPE size_type;

    /// The type of the particle values
    typedef T value_type;

#ifdef VSMC_USE_SEQUENTIAL_RNG
    /// The type of the sequential pseudo random number generator C++11 engine
    typedef VSMC_SEQRNG_TYPE rng_type;
#else
    /// The type of the Counter-based random number generator
    typedef VSMC_CBRNG_TYPE cbrng_type;

    /// The type of the Counter-based random number generator C++11 engine
    typedef rng::Engine<cbrng_type> rng_type;
#endif

    /// The integer type of the seed
    typedef rng_type::result_type seed_type;

    /// The type of the weight and log weight vectors
    typedef Eigen::VectorXd weight_type;

    /// \brief Construct a Particle object with a given number of particles
    ///
    /// \param N The number of particles
    /// \param seed The seed to the parallel RNG system
    ///
    /// \post All weights are initialized to be euqal to each other
    explicit Particle (size_type N, seed_type seed = VSMC_RNG_SEED) :
        size_(N), value_(N), ess_(N),
        weight_(N), log_weight_(N), inc_weight_(N), replication_(N),
        ess_cached_(false), weight_cached_(false), log_weight_cached_(false),
        resampled_(false), zconst_(0), seed_(seed)
#ifndef VSMC_USE_SEQUENTIAL_RNG
        , prng_(N)
#endif
    {
        reset_rng();
        set_equal_weight();
    }

    /// Size of the particle set
    size_type size () const
    {
        return size_;
    }

    /// Read and write access to particle values
    value_type &value ()
    {
        return value_;
    }

    /// Read only access to particle values
    const value_type &value () const
    {
        return value_;
    }

    /// Read only access to the weights
    const weight_type &weight () const
    {
        if (!weight_cached_) {
            weight_ = log_weight().array().exp();
            double sum = weight_.sum();
            weight_ *= 1 / sum;
            weight_cached_ = true;
        }

        return weight_;
    }

    /// Read only access to the log weights
    const weight_type &log_weight () const
    {
        if (!log_weight_cached_) {
            double max_weight = log_weight_.maxCoeff();
            log_weight_ = log_weight_.array() - max_weight;
            log_weight_cached_ = true;
        }

        return log_weight_;
    }

    /// Set equal weights for all particles
    void set_equal_weight ()
    {
        ess_ = size_;
        weight_.setConstant(1.0 / size_);
        log_weight_.setConstant(0);

        ess_cached_ = true;
        weight_cached_ = true;
        log_weight_cached_ = true;
    }

    /// \brief Set the log weights with a pointer
    ///
    /// \param new_weight The position to start the reading, it shall be valid
    /// after increments of size() times.
    /// \param delta A multiplier appiled to the new log weights
    void set_log_weight (const double *new_weight, double delta = 1)
    {
        Eigen::Map<const weight_type> w(new_weight, size_);
        set_log_weight(w, delta);
    }

    /// Set the log weights with a weight_type object
    void set_log_weight (const weight_type &new_weight, double delta = 1)
    {
        log_weight_ = delta * new_weight.head(size_);
        set_log_weight();
    }

    /// \brief Add to the log weights with a pointer
    ///
    /// \param inc_weight The position to start the reading, it shall be valid
    /// after increments of size() times.
    /// \param delta A multiplier appiled to the new incremental log weights
    /// \param add_zconst Whether this incremental weights shall contribute to
    /// the SMC normalizing constant estimate
    void add_log_weight (const double *inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        Eigen::Map<const weight_type> w(inc_weight, size_);
        add_log_weight(w, delta, add_zconst);
    }

    /// Add to the log weights with a weight_object object
    void add_log_weight (const weight_type &inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        using std::log;

        inc_weight_ = delta * inc_weight.head(size_);
        log_weight_ += inc_weight_;
        if (add_zconst)
            zconst_ += log(weight().dot(inc_weight_.array().exp().matrix()));
        set_log_weight();
    }

    /// The current ESS (Effective Sample Size)
    double ess () const
    {
        if (!ess_cached_) {
            ess_ = 1 / weight().squaredNorm();
            ess_cached_ = true;
        }

        return ess_;
    }

    /// Whether resampling was performed when resampling(scheme, threshold) was
    /// last called.
    bool resampled () const
    {
        return resampled_;
    }

    /// Get the value of the logarithm of SMC normalizing constant
    double zconst () const
    {
        return zconst_;
    }

    /// Reset the value of logarithm of SMC normalizing constant to zero
    void reset_zconst ()
    {
        zconst_ = 0;
    }

    /// \brief Perform resampling if ess() < threshold * size()
    ///
    /// \param scheme The resampling scheme, see ResamplingScheme
    /// \param threshold The threshold for resampling
    void resample (ResampleScheme scheme, double threshold)
    {
        assert(replication_.size() == size());

        // call to ess() will normalize weight first
        resampled_ = ess() < threshold * size_;

        if (resampled_) {
            internal::pre_resampling(&value_);
            switch (scheme) {
                case MULTINOMIAL :
                    resample_multinomial();
                    break;
                case RESIDUAL :
                    resample_residual();
                    break;
                case STRATIFIED :
                    resample_stratified();
                    break;
                case SYSTEMATIC :
                    resample_systematic();
                    break;
                case RESIDUAL_STRATIFIED :
                    resample_residual_stratified ();
                    break;
                default :
                    resample_stratified();
                    break;
            }
            resample_do();
            internal::post_resampling(&value_);
        }
    }

    /// \brief Get a C++11 RNG engine
    ///
    /// \param id The position of the particle, 0 to size() - 1
    ///
    /// \return A reference to a C++11 RNG engine unique to particle at
    /// position id, and independent of others if \c VSMC_USE_SEQUENTIAL_RNG is
    /// not defined. Otherwise, it is the same pseudo RNG for any value of \c
    /// id
    rng_type &rng (size_type id)
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        return srng_;
#else
        return prng_[id];
#endif
    }

    /// Reset the RNG system with a given seed
    void reset_rng (seed_type seed)
    {
        seed_ = seed;
        reset_rng();
    }

    /// Reset the parallel RNG system with the last used seed
    void reset_rng ()
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        srng_ = rng_type(seed_);
#else
        for (size_type i = 0; i != size_; ++i)
            prng_[i] = rng_type(seed_ + i);
#endif
    }

    private :

    typedef Eigen::Matrix<size_type, Eigen::Dynamic, 1> replication_type;

    size_type size_;
    value_type value_;
    mutable double ess_;

    mutable weight_type weight_;
    mutable weight_type log_weight_;
    mutable weight_type inc_weight_;
    mutable replication_type replication_;

    mutable bool ess_cached_;
    mutable bool weight_cached_;
    mutable bool log_weight_cached_;

    bool resampled_;
    double zconst_;

    seed_type seed_;
#ifdef VSMC_USE_SEQUENTIAL_RNG
    rng_type srng_;
#else
    std::deque<rng_type> prng_;
#endif

    void set_log_weight ()
    {
        ess_cached_ = false;
        weight_cached_ = false;
        log_weight_cached_ = false;

        assert(weight_.size() == size_);
        assert(log_weight_.size() == size_);
        assert(inc_weight_.size() == size_);
    }

    void resample_multinomial ()
    {
        weight2replication(size_);
    }

    void resample_residual ()
    {
        /// \internal Reuse weight and log_weight. weight: act as the
        /// fractional part of N * weight. log_weight: act as the integral
        /// part of N * weight.  They all will be reset to equal weights after
        /// resampling.  So it is safe to modify them here.

        using std::modf;

        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        weight2replication(weight_.sum());
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_stratified ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_systematic ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_residual_stratified ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_residual_systematic ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void weight2replication (size_type size)
    {
        double tp = weight_.sum();
        double sum_p = 0;
        size_type sum_n = 0;
        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i) {
            if (sum_n < size && weight_[i] > 0) {
                rng::binomial_distribution<size_type> binom(
                        size - sum_n, weight_[i] / (tp - sum_p));
                replication_[i] = binom(rng(i));
            }
            sum_p += weight_[i];
            sum_n += replication_[i];
        }
    }

    void resample_do ()
    {
        // Some times the nuemrical round error can cause the total childs
        // differ from number of particles
        size_type sum = replication_.sum();
        if (sum != size_) {
            size_type id_max;
            replication_.maxCoeff(&id_max);
            replication_[id_max] += size_ - sum;
        }

        size_type from = 0;
        size_type time = 0;
        for (size_type to = 0; to != size_; ++to) {
            if (!replication_[to]) {
                // replication_[to] has zero child, copy from elsewhere
                if (replication_[from] - time <= 1) {
                    // only 1 child left on replication_[from]
                    time = 0;
                    do // move from to some position with at least 2 children
                        ++from;
                    while (replication_[from] < 2);
                }
                value_.copy(from, to);
                ++time;
            }
        }
        set_equal_weight();
    }
}; // class Particle

} // namespace vsmc

#endif // VSMC_CORE_PARTICLE_HPP
<commit_msg>Use DenseBase as input to weight mutators<commit_after>#ifndef VSMC_CORE_PARTICLE_HPP
#define VSMC_CORE_PARTICLE_HPP

#include <vsmc/internal/common.hpp>
#include <vsmc/internal/resampling.hpp>

namespace vsmc {

/// \brief Particle class representing the whole particle set
/// \ingroup Core
///
/// \tparam T Requirement:
/// \li Constructor compatible with
/// \code T(Particle<T>::size_type N) \endcode
/// \li member function copy method compatible with
/// \code copy(Particle<T>::size_type from, Particle<T>::size_type to) \endcode
template <typename T>
class Particle
{
    public :

    /// The type of the number of particles
    typedef VSMC_SIZE_TYPE size_type;

    /// The type of the particle values
    typedef T value_type;

#ifdef VSMC_USE_SEQUENTIAL_RNG
    /// The type of the sequential pseudo random number generator C++11 engine
    typedef VSMC_SEQRNG_TYPE rng_type;
#else
    /// The type of the Counter-based random number generator
    typedef VSMC_CBRNG_TYPE cbrng_type;

    /// The type of the Counter-based random number generator C++11 engine
    typedef rng::Engine<cbrng_type> rng_type;
#endif

    /// The integer type of the seed
    typedef rng_type::result_type seed_type;

    /// The type of the weight and log weight vectors
    typedef Eigen::VectorXd weight_type;

    /// \brief Construct a Particle object with a given number of particles
    ///
    /// \param N The number of particles
    /// \param seed The seed to the parallel RNG system
    ///
    /// \post All weights are initialized to be euqal to each other
    explicit Particle (size_type N, seed_type seed = VSMC_RNG_SEED) :
        size_(N), value_(N), ess_(N),
        weight_(N), log_weight_(N), inc_weight_(N), replication_(N),
        ess_cached_(false), weight_cached_(false), log_weight_cached_(false),
        resampled_(false), zconst_(0), seed_(seed)
#ifndef VSMC_USE_SEQUENTIAL_RNG
        , prng_(N)
#endif
    {
        reset_rng();
        set_equal_weight();
    }

    /// Size of the particle set
    size_type size () const
    {
        return size_;
    }

    /// Read and write access to particle values
    value_type &value ()
    {
        return value_;
    }

    /// Read only access to particle values
    const value_type &value () const
    {
        return value_;
    }

    /// Read only access to the weights
    const weight_type &weight () const
    {
        if (!weight_cached_) {
            weight_ = log_weight().array().exp();
            double sum = weight_.sum();
            weight_ *= 1 / sum;
            weight_cached_ = true;
        }

        return weight_;
    }

    /// Read only access to the log weights
    const weight_type &log_weight () const
    {
        if (!log_weight_cached_) {
            double max_weight = log_weight_.maxCoeff();
            log_weight_ = log_weight_.array() - max_weight;
            log_weight_cached_ = true;
        }

        return log_weight_;
    }

    /// Set equal weights for all particles
    void set_equal_weight ()
    {
        ess_ = size_;
        weight_.setConstant(1.0 / size_);
        log_weight_.setConstant(0);

        ess_cached_ = true;
        weight_cached_ = true;
        log_weight_cached_ = true;
    }

    /// \brief Set the log weights with a pointer
    ///
    /// \param new_weight The position to start the reading, it shall be valid
    /// after increments of size() times.
    /// \param delta A multiplier appiled to the new log weights
    void set_log_weight (const double *new_weight, double delta = 1)
    {
        Eigen::Map<const weight_type> w(new_weight, size_);
        set_log_weight(w, delta);
    }

    /// Set the log weights with a weight_type object
    template <typename Derived>
    void set_log_weight (const Eigen::DenseBase<Derived> &new_weight,
            double delta = 1)
    {
        log_weight_ = delta * new_weight.head(size_);
        set_log_weight();
    }

    /// \brief Add to the log weights with a pointer
    ///
    /// \param inc_weight The position to start the reading, it shall be valid
    /// after increments of size() times.
    /// \param delta A multiplier appiled to the new incremental log weights
    /// \param add_zconst Whether this incremental weights shall contribute to
    /// the SMC normalizing constant estimate
    void add_log_weight (const double *inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        Eigen::Map<const weight_type> w(inc_weight, size_);
        add_log_weight(w, delta, add_zconst);
    }

    /// Add to the log weights with a weight_object object
    template <typename Derived>
    void add_log_weight (const Eigen::DenseBase<Derived> &inc_weight,
            double delta = 1, bool add_zconst = true)
    {
        using std::log;

        inc_weight_ = delta * inc_weight.head(size_);
        log_weight_ += inc_weight_;
        if (add_zconst)
            zconst_ += log(weight().dot(inc_weight_.array().exp().matrix()));
        set_log_weight();
    }

    /// The current ESS (Effective Sample Size)
    double ess () const
    {
        if (!ess_cached_) {
            ess_ = 1 / weight().squaredNorm();
            ess_cached_ = true;
        }

        return ess_;
    }

    /// Whether resampling was performed when resampling(scheme, threshold) was
    /// last called.
    bool resampled () const
    {
        return resampled_;
    }

    /// Get the value of the logarithm of SMC normalizing constant
    double zconst () const
    {
        return zconst_;
    }

    /// Reset the value of logarithm of SMC normalizing constant to zero
    void reset_zconst ()
    {
        zconst_ = 0;
    }

    /// \brief Perform resampling if ess() < threshold * size()
    ///
    /// \param scheme The resampling scheme, see ResamplingScheme
    /// \param threshold The threshold for resampling
    void resample (ResampleScheme scheme, double threshold)
    {
        assert(replication_.size() == size());

        // call to ess() will normalize weight first
        resampled_ = ess() < threshold * size_;

        if (resampled_) {
            internal::pre_resampling(&value_);
            switch (scheme) {
                case MULTINOMIAL :
                    resample_multinomial();
                    break;
                case RESIDUAL :
                    resample_residual();
                    break;
                case STRATIFIED :
                    resample_stratified();
                    break;
                case SYSTEMATIC :
                    resample_systematic();
                    break;
                case RESIDUAL_STRATIFIED :
                    resample_residual_stratified ();
                    break;
                default :
                    resample_stratified();
                    break;
            }
            resample_do();
            internal::post_resampling(&value_);
        }
    }

    /// \brief Get a C++11 RNG engine
    ///
    /// \param id The position of the particle, 0 to size() - 1
    ///
    /// \return A reference to a C++11 RNG engine unique to particle at
    /// position id, and independent of others if \c VSMC_USE_SEQUENTIAL_RNG is
    /// not defined. Otherwise, it is the same pseudo RNG for any value of \c
    /// id
    rng_type &rng (size_type id)
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        return srng_;
#else
        return prng_[id];
#endif
    }

    /// Reset the RNG system with a given seed
    void reset_rng (seed_type seed)
    {
        seed_ = seed;
        reset_rng();
    }

    /// Reset the parallel RNG system with the last used seed
    void reset_rng ()
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        srng_ = rng_type(seed_);
#else
        for (size_type i = 0; i != size_; ++i)
            prng_[i] = rng_type(seed_ + i);
#endif
    }

    private :

    typedef Eigen::Matrix<size_type, Eigen::Dynamic, 1> replication_type;

    size_type size_;
    value_type value_;
    mutable double ess_;

    mutable weight_type weight_;
    mutable weight_type log_weight_;
    mutable weight_type inc_weight_;
    mutable replication_type replication_;

    mutable bool ess_cached_;
    mutable bool weight_cached_;
    mutable bool log_weight_cached_;

    bool resampled_;
    double zconst_;

    seed_type seed_;
#ifdef VSMC_USE_SEQUENTIAL_RNG
    rng_type srng_;
#else
    std::deque<rng_type> prng_;
#endif

    void set_log_weight ()
    {
        ess_cached_ = false;
        weight_cached_ = false;
        log_weight_cached_ = false;

        assert(weight_.size() == size_);
        assert(log_weight_.size() == size_);
        assert(inc_weight_.size() == size_);
    }

    void resample_multinomial ()
    {
        weight2replication(size_);
    }

    void resample_residual ()
    {
        /// \internal Reuse weight and log_weight. weight: act as the
        /// fractional part of N * weight. log_weight: act as the integral
        /// part of N * weight.  They all will be reset to equal weights after
        /// resampling.  So it is safe to modify them here.

        using std::modf;

        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        weight2replication(weight_.sum());
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_stratified ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_systematic ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_residual_stratified ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_residual_systematic ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void weight2replication (size_type size)
    {
        double tp = weight_.sum();
        double sum_p = 0;
        size_type sum_n = 0;
        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i) {
            if (sum_n < size && weight_[i] > 0) {
                rng::binomial_distribution<size_type> binom(
                        size - sum_n, weight_[i] / (tp - sum_p));
                replication_[i] = binom(rng(i));
            }
            sum_p += weight_[i];
            sum_n += replication_[i];
        }
    }

    void resample_do ()
    {
        // Some times the nuemrical round error can cause the total childs
        // differ from number of particles
        size_type sum = replication_.sum();
        if (sum != size_) {
            size_type id_max;
            replication_.maxCoeff(&id_max);
            replication_[id_max] += size_ - sum;
        }

        size_type from = 0;
        size_type time = 0;
        for (size_type to = 0; to != size_; ++to) {
            if (!replication_[to]) {
                // replication_[to] has zero child, copy from elsewhere
                if (replication_[from] - time <= 1) {
                    // only 1 child left on replication_[from]
                    time = 0;
                    do // move from to some position with at least 2 children
                        ++from;
                    while (replication_[from] < 2);
                }
                value_.copy(from, to);
                ++time;
            }
        }
        set_equal_weight();
    }
}; // class Particle

} // namespace vsmc

#endif // VSMC_CORE_PARTICLE_HPP
<|endoftext|>