<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include <mapnik/ptree_helpers.hpp>

using std::clog;
using std::endl;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(ogr_datasource)

using mapnik::Envelope;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;

ogr_datasource::ogr_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     type_(datasource::Vector),
     desc_(*params.get<std::string>("type"),"utf-8")
{
   OGRRegisterAll();

   boost::optional<std::string> file = params.get<std::string>("file");
   if (!file) throw datasource_exception("missing <file> paramater");

   boost::optional<std::string> layer = params.get<std::string>("layer");
   if (!layer) throw datasource_exception("missing <layer> paramater");

   layerName_ = *layer;
   multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);

   dataset_ = OGRSFDriverRegistrar::Open ((*file).c_str(), FALSE);
   if (!dataset_) throw datasource_exception(CPLGetLastErrorMsg());

   layer_ = dataset_->GetLayerByName (layerName_.c_str());
   if (! layer_) throw datasource_exception("cannot find <layer> in dataset");

   OGREnvelope envelope;
   layer_->GetExtent (&envelope);
   extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY);

   OGRFeatureDefn* def = layer_->GetLayerDefn ();
   if (def != 0)
   {
       int fld_count = def->GetFieldCount ();
       for (int i = 0; i < fld_count; i++)
       {
           OGRFieldDefn* fld = def->GetFieldDefn (i);

           std_string fld_name = fld->GetNameRef ();
           OGRFieldType type_oid = fld->GetType ();

           switch (type_oid)
           {
           case OFTInteger:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
               break;

           case OFTReal:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
               break;

           case OFTString:
           case OFTWideString: // deprecated
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
               break;

           case OFTBinary:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           case OFTIntegerList:
           case OFTRealList:
           case OFTStringList:
           case OFTWideStringList: // deprecated !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               break;

           case OFTDate:
           case OFTTime:
           case OFTDateTime: // unhandled !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           default: // unknown
#ifdef MAPNIK_DEBUG
               clog << "unknown type_oid=" << type_oid << endl;
#endif
               break;
           }
       }
   }
}

ogr_datasource::~ogr_datasource()
{
    OGRDataSource::DestroyDataSource (dataset_);
}

std::string const ogr_datasource::name_="ogr";

std::string ogr_datasource::name()
{
   return name_;
}

int ogr_datasource::type() const
{
   return type_;
}

Envelope<double> ogr_datasource::envelope() const
{
   return extent_;
}

layer_descriptor ogr_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr ogr_datasource::features(query const& q) const
{
   if (dataset_ && layer_)
   {
        mapnik::Envelope<double> const& query_extent = q.get_bbox();

        layer_->SetSpatialFilterRect (query_extent.minx(),
                                      query_extent.miny(),
                                      query_extent.maxx(),
                                      query_extent.maxy());

#if 0
        std::ostringstream s;

        s << "select ";
        std::set<std::string> const& props=q.property_names();
        std::set<std::string>::const_iterator pos=props.begin();
        std::set<std::string>::const_iterator end=props.end();
        while (pos != end)
        {
           s <<",\""<<*pos<<"\"";
           ++pos;
        }
        s << " from " << layerName_ ;

        // execute existing SQL
        OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly);

        // layer must be freed
        dataset_->ReleaseResultSet (layer);
#endif

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
   return featureset_ptr();
}

featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
{
   if (dataset_ && layer_)
   {
        OGRPoint point;
	    point.setX (pt.x);
	    point.setY (pt.y);

        layer_->SetSpatialFilter (&point);

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
   return featureset_ptr();
}

<commit_msg>+ apply ogr_6th_revision.patch to allow unicode support<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include <mapnik/ptree_helpers.hpp>

using std::clog;
using std::endl;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(ogr_datasource)

using mapnik::Envelope;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;

ogr_datasource::ogr_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     type_(datasource::Vector),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8"))
{
   OGRRegisterAll();

   boost::optional<std::string> file = params.get<std::string>("file");
   if (!file) throw datasource_exception("missing <file> paramater");

   boost::optional<std::string> layer = params.get<std::string>("layer");
   if (!layer) throw datasource_exception("missing <layer> paramater");

   layerName_ = *layer;
   multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);

   dataset_ = OGRSFDriverRegistrar::Open ((*file).c_str(), FALSE);
   if (!dataset_) throw datasource_exception(CPLGetLastErrorMsg());

   layer_ = dataset_->GetLayerByName (layerName_.c_str());
   if (! layer_) throw datasource_exception("cannot find <layer> in dataset");

   OGREnvelope envelope;
   layer_->GetExtent (&envelope);
   extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY);

   OGRFeatureDefn* def = layer_->GetLayerDefn ();
   if (def != 0)
   {
       int fld_count = def->GetFieldCount ();
       for (int i = 0; i < fld_count; i++)
       {
           OGRFieldDefn* fld = def->GetFieldDefn (i);

           std_string fld_name = fld->GetNameRef ();
           OGRFieldType type_oid = fld->GetType ();

           switch (type_oid)
           {
           case OFTInteger:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
               break;

           case OFTReal:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
               break;

           case OFTString:
           case OFTWideString: // deprecated
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
               break;

           case OFTBinary:
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           case OFTIntegerList:
           case OFTRealList:
           case OFTStringList:
           case OFTWideStringList: // deprecated !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               break;

           case OFTDate:
           case OFTTime:
           case OFTDateTime: // unhandled !
#ifdef MAPNIK_DEBUG
               clog << "unhandled type_oid=" << type_oid << endl;
#endif
               desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object));
               break;

           default: // unknown
#ifdef MAPNIK_DEBUG
               clog << "unknown type_oid=" << type_oid << endl;
#endif
               break;
           }
       }
   }
}

ogr_datasource::~ogr_datasource()
{
    OGRDataSource::DestroyDataSource (dataset_);
}

std::string const ogr_datasource::name_="ogr";

std::string ogr_datasource::name()
{
   return name_;
}

int ogr_datasource::type() const
{
   return type_;
}

Envelope<double> ogr_datasource::envelope() const
{
   return extent_;
}

layer_descriptor ogr_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr ogr_datasource::features(query const& q) const
{
   if (dataset_ && layer_)
   {
        mapnik::Envelope<double> const& query_extent = q.get_bbox();

        layer_->SetSpatialFilterRect (query_extent.minx(),
                                      query_extent.miny(),
                                      query_extent.maxx(),
                                      query_extent.maxy());

#if 0
        std::ostringstream s;

        s << "select ";
        std::set<std::string> const& props=q.property_names();
        std::set<std::string>::const_iterator pos=props.begin();
        std::set<std::string>::const_iterator end=props.end();
        while (pos != end)
        {
           s <<",\""<<*pos<<"\"";
           ++pos;
        }
        s << " from " << layerName_ ;

        // execute existing SQL
        OGRLayer* layer = dataset_->ExecuteSQL (s.str(), poly);

        // layer must be freed
        dataset_->ReleaseResultSet (layer);
#endif

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
   return featureset_ptr();
}

featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const
{
   if (dataset_ && layer_)
   {
        OGRPoint point;
	    point.setX (pt.x);
	    point.setY (pt.y);

        layer_->SetSpatialFilter (&point);

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
   return featureset_ptr();
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: connection.hpp 17 2005-03-08 23:58:43Z pavlenko $

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>

extern "C"
{
#include "libpq-fe.h"
}

#include "resultset.hpp"

class ResultSet;
class Connection
{
   private:
      PGconn *conn_;
      int cursorId;
      bool closed_;
   public:
      Connection(std::string const& connection_str)
         :cursorId(0),
         closed_(false)
      {
         conn_=PQconnectdb(connection_str.c_str());
         if (PQstatus(conn_) != CONNECTION_OK)
         {
             std::string s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":" << std::endl << msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s );
         }
      }

      bool execute(const std::string& sql) const
      {
         PGresult *result=PQexec(conn_,sql.c_str());
         bool ok=(result && PQresultStatus(result)==PGRES_COMMAND_OK);
         PQclear(result);
         return ok;
      }

      boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
      {
         PGresult *result=0;
         if (type==1)
         {
             result=PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
         }
         else
         {
             result=PQexec(conn_,sql.c_str());
         }
         if(!result || PQresultStatus(result) != PGRES_TUPLES_OK)
         {
             std::string s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":" << std::endl << msg.substr( 0, msg.size() - 1 );
                 }

                 s << std::endl << "Full sql was: '" + sql + "'" << std::endl;
             }
             throw mapnik::datasource_exception( s );
         }

         return boost::shared_ptr<ResultSet>(new ResultSet(result));
      }

      std::string client_encoding() const
      {
         return PQparameterStatus(conn_,"client_encoding");
      }

      bool isOK() const
      {
         return (PQstatus(conn_)!=CONNECTION_BAD);
      }

      void close()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: datasource closed, also closing connection - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }

      std::string new_cursor_name()
      {
          std::ostringstream s;
          s << "mapnik_" << (cursorId++);
          return s.str();
      }

      ~Connection()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: postgresql connection closed - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }
};

#endif //CONNECTION_HPP
<commit_msg>avoid compiler errors on os x<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: connection.hpp 17 2005-03-08 23:58:43Z pavlenko $

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>

extern "C"
{
#include "libpq-fe.h"
}

#include "resultset.hpp"

class ResultSet;
class Connection
{
   private:
      PGconn *conn_;
      int cursorId;
      bool closed_;
   public:
      Connection(std::string const& connection_str)
         :cursorId(0),
         closed_(false)
      {
         conn_=PQconnectdb(connection_str.c_str());
         if (PQstatus(conn_) != CONNECTION_OK)
         {
             std::ostringstream s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":\n" << msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s.str() );
         }
      }

      bool execute(const std::string& sql) const
      {
         PGresult *result=PQexec(conn_,sql.c_str());
         bool ok=(result && PQresultStatus(result)==PGRES_COMMAND_OK);
         PQclear(result);
         return ok;
      }

      boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
      {
         PGresult *result=0;
         if (type==1)
         {
             result=PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
         }
         else
         {
             result=PQexec(conn_,sql.c_str());
         }
         if(!result || PQresultStatus(result) != PGRES_TUPLES_OK)
         {
             std::ostringstream s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":" << std::endl << msg.substr( 0, msg.size() - 1 );
                 }

                 s << std::endl << "Full sql was: '" + sql + "'" << std::endl;
             }
             throw mapnik::datasource_exception( s.str() );
         }

         return boost::shared_ptr<ResultSet>(new ResultSet(result));
      }

      std::string client_encoding() const
      {
         return PQparameterStatus(conn_,"client_encoding");
      }

      bool isOK() const
      {
         return (PQstatus(conn_)!=CONNECTION_BAD);
      }

      void close()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: datasource closed, also closing connection - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }

      std::string new_cursor_name()
      {
          std::ostringstream s;
          s << "mapnik_" << (cursorId++);
          return s.str();
      }

      ~Connection()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: postgresql connection closed - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }
};

#endif //CONNECTION_HPP
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: connection.hpp 17 2005-03-08 23:58:43Z pavlenko $

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>

extern "C"
{
#include "libpq-fe.h"
}

#include "resultset.hpp"

class ResultSet;
class Connection
{
   private:
      PGconn *conn_;
      int cursorId;
   public:
      Connection(std::string const& connection_str)
         :cursorId(0)
      {
         conn_=PQconnectdb(connection_str.c_str());
         if (PQstatus(conn_) != CONNECTION_OK)
         {
             std::string s("PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s += ":\n" + msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s );
         }
      }

      bool execute(const std::string& sql) const
      {
         PGresult *result=PQexec(conn_,sql.c_str());
         bool ok=(result && PQresultStatus(result)==PGRES_COMMAND_OK);
         PQclear(result);
         return ok;
      }
      boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
      {
         PGresult *result=0;
         if (type==1)
         {
             result=PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
         }
         else
         {
             result=PQexec(conn_,sql.c_str());
         }
         if(!result || PQresultStatus(result) != PGRES_TUPLES_OK)
         {
             std::string s("PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s += ":\n" + msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s );
         }

         return boost::shared_ptr<ResultSet>(new ResultSet(result));
      }

      std::string client_encoding() const
      {
         return PQparameterStatus(conn_,"client_encoding");
      }

      bool isOK() const
      {
         return (PQstatus(conn_)!=CONNECTION_BAD);
      }

      void close()
      {
         PQfinish(conn_);
      }

      std::string new_cursor_name()
      {
          std::ostringstream s;
          s << "mapnik_" << (cursorId++);
          return s.str();
      }

      ~Connection()
      {
         PQfinish(conn_);
#ifdef MAPNIK_DEBUG
         std::clog << "close connection " << conn_ << "\n";
#endif
      }
};

#endif //CONNECTION_HPP
<commit_msg>when a SQL query sent to postgres fails, output the whole thing so users know what mapnik tried to send (as the PSQL error hint truncates the sql)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: connection.hpp 17 2005-03-08 23:58:43Z pavlenko $

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>

extern "C"
{
#include "libpq-fe.h"
}

#include "resultset.hpp"

class ResultSet;
class Connection
{
   private:
      PGconn *conn_;
      int cursorId;
   public:
      Connection(std::string const& connection_str)
         :cursorId(0)
      {
         conn_=PQconnectdb(connection_str.c_str());
         if (PQstatus(conn_) != CONNECTION_OK)
         {
             std::string s("PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s += ":\n" + msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s );
         }
      }

      bool execute(const std::string& sql) const
      {
         PGresult *result=PQexec(conn_,sql.c_str());
         bool ok=(result && PQresultStatus(result)==PGRES_COMMAND_OK);
         PQclear(result);
         return ok;
      }
      boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
      {
         PGresult *result=0;
         if (type==1)
         {
             result=PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
         }
         else
         {
             result=PQexec(conn_,sql.c_str());
         }
         if(!result || PQresultStatus(result) != PGRES_TUPLES_OK)
         {
             std::string s("PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s += ":\n" + msg.substr( 0, msg.size() - 1 );
                 }

                 s += "\nFull sql was: '" + sql + "'\n";
             }
             throw mapnik::datasource_exception( s );
         }

         return boost::shared_ptr<ResultSet>(new ResultSet(result));
      }

      std::string client_encoding() const
      {
         return PQparameterStatus(conn_,"client_encoding");
      }

      bool isOK() const
      {
         return (PQstatus(conn_)!=CONNECTION_BAD);
      }

      void close()
      {
         PQfinish(conn_);
      }

      std::string new_cursor_name()
      {
          std::ostringstream s;
          s << "mapnik_" << (cursorId++);
          return s.str();
      }

      ~Connection()
      {
         PQfinish(conn_);
#ifdef MAPNIK_DEBUG
         std::clog << "close connection " << conn_ << "\n";
#endif
      }
};

#endif //CONNECTION_HPP
<|endoftext|>


<commit_before>#ifndef __ETERNAL_TCP_HEADERS__
#define __ETERNAL_TCP_HEADERS__

#include <errno.h>
#include <pthread.h> /* POSIX Threads */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include <algorithm>
#include <array>
#include <exception>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <sstream>
#include <streambuf>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <boost/circular_buffer.hpp>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include <google/protobuf/message.h>
#include "ET.pb.h"

using namespace std;

namespace et {
void equalOrFatal(ssize_t expected, ssize_t actual);
}

#define FATAL_FAIL(X) \
  if ((X == -1)) LOG(FATAL) << "Error: (" << errno << "): " << strerror(errno);

#endif
<commit_msg>Add missing header<commit_after>#ifndef __ETERNAL_TCP_HEADERS__
#define __ETERNAL_TCP_HEADERS__

#include <errno.h>
#include <pthread.h> /* POSIX Threads */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>

#include <algorithm>
#include <array>
#include <exception>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <sstream>
#include <streambuf>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <boost/circular_buffer.hpp>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include <google/protobuf/message.h>
#include "ET.pb.h"

using namespace std;

namespace et {
void equalOrFatal(ssize_t expected, ssize_t actual);
}

#define FATAL_FAIL(X) \
  if ((X == -1)) LOG(FATAL) << "Error: (" << errno << "): " << strerror(errno);

#endif
<|endoftext|>


<commit_before>// header file for storing integration schemes
#include "IBSolver.h"

#include "Geometry.h"
#include "ProjectionSolver.h"
#include "ConjugateGradientSolver.h"
#include "CholeskySolver.h"
#include "BoundaryVector.h"
#include "Grid.h"
#include "State.h"
#include "VectorOperations.h"
#include <string>

using namespace std;

namespace ibpm {

IBSolver::IBSolver(
	const Grid& grid,
	NavierStokesModel& model,
	double dt,
	Scheme::SchemeType scheme
	) :
	_grid( grid ),
	_scheme( scheme ),
	_name( _scheme.name( ) ),
	_dt( dt ),
	_model( model ),
	_Nprev( grid ),
	_Ntemp( grid ),
	_oldSaved( false ),
	_solver( _scheme.nsteps() ),
    _tol( 1e-7) {
		createAllSolvers();
	}

IBSolver::IBSolver(
    const Grid& grid,
    NavierStokesModel& model,
    double dt,
    Scheme::SchemeType scheme,
    double tol
    ) :
    _grid( grid ),
    _scheme( scheme ),
    _name( _scheme.name( ) ),
    _dt( dt ),
    _model( model ),
    _Nprev( grid ),
    _Ntemp( grid ),
    _oldSaved( false ),
    _solver( _scheme.nsteps() ),
    _tol( tol ) {
        createAllSolvers();
}

IBSolver::~IBSolver() {
	deleteAllSolvers();
}

string IBSolver::getName() {
	return _name;
}

string IBSolver::getTimestep() {
    return _dt;
}

void IBSolver::init() {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		_solver[i] -> init();
	}
}

void IBSolver::reset() {
    _oldSaved = false;
}

bool IBSolver::load(const string& basename) {
	bool successInit = false;
	bool successTemp = true;
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		char num[256];
		sprintf( num, "%02d", i+1 );
		string filename = basename + "_" + num;
		successTemp = _solver[i] -> load( filename ) && successTemp;
        if ( i == 0 ) {
            successInit = true;
        }
	}

	return successInit && successTemp;
}

bool IBSolver::save(const string& basename) {
	bool successInit = false;
	bool successTemp = true;
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		char num[256];
		sprintf( num, "%02d", i+1 );
		string filename = basename + "_" + num;

		successTemp = _solver[i] -> save( filename ) && successTemp;
		if ( i == 0 ) {
            successInit = true;
        }
	}

	return successInit && successTemp;
}

void IBSolver::createAllSolvers() {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		_solver[i] = createSolver( ( _scheme.an(i) + _scheme.bn(i) )*_dt );
	}
}

void IBSolver::deleteAllSolvers() {
	for (unsigned int i = 0; i < _solver.size(); i++) {
		delete _solver[i];
	}
}

ProjectionSolver* IBSolver::createSolver(double beta) {
	// Check whether all bodies are stationary
	//      If so, return a CholeskySolver
	//      If not, return a ConjugateGradientSolver
	if ( _model.isTimeDependent() ) {
		cerr << "Using ConjugateGradient solver for projection step" << endl
		<< "  tolerance = " << _tol << endl;
		return new ConjugateGradientSolver( _grid, _model, beta, _tol );
	}
	else {
		cerr << "Using Cholesky solver for projection step" << endl;
		return new CholeskySolver( _grid, _model, beta );
	}
}

void IBSolver::setTol( double tol ) {
    _tol = tol;
    createAllSolvers();
}

void IBSolver::advance( State& x ) {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		Scalar nonlinear = N(x);
		advanceSubstep( x, nonlinear, i );
	}

	x.time += _dt;
	++x.timestep;
}

void IBSolver::advance( State& x, const Scalar& Bu ) {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		Scalar nonlinear = N(x) + Bu;
		advanceSubstep( x, nonlinear, i );
	}

    x.time += _dt;
	++x.timestep;
}

void IBSolver::advanceSubstep( State& x, const Scalar& nonlinear, int i ) {
	// If the body is moving, update the positions of the bodies
	if ( _model.isTimeDependent() ) {
		_model.updateOperators( x.time + _scheme.cn(i) * _dt );
	}

	// Evaluate Right-Hand-Side (a) for first equation of ProjectionSolver
	Scalar a = Laplacian( x.omega );
	a *= 0.5 * _model.getAlpha() * ( _scheme.an(i) + _scheme.bn(i) );
	a += _scheme.an(i)*nonlinear;

	if ( _scheme.bn(i) != 0 ) {
        // for ab2
		if ( _oldSaved == false ) {
			_Nprev = nonlinear;
		}

		a += _scheme.bn(i) * _Nprev;
	}

	a *= _dt;
	a += x.omega;

	// Evaluate Right-Hand-Side (b) for second equation of ProjectionSolver
	BoundaryVector b = _model.getConstraints();

	// Call the ProjectionSolver to determine the vorticity and forces
	_solver[i]->solve( a, b, x.omega, x.f );

	// Update the state, for instance to compute the corresponding flux
	_model.refreshState( x );
	_Nprev = nonlinear;

    if( _oldSaved == false ) {
        _oldSaved = true;
    }
}

// ===================== //
// Derived class methods //
// ===================== //

Scalar NonlinearIBSolver::N(const State& x) const {
	Flux v = CrossProduct( x.q, x.omega );
	Scalar g = Curl( v );
	return g;
}

Scalar LinearizedIBSolver::N(const State& x) const {
	Flux v = CrossProduct( _x0.q, x.omega );
	v += CrossProduct( x.q, _x0.omega );
	Scalar g = Curl( v );
	return g;
}

Scalar AdjointIBSolver::N(const State& x) const {
    Scalar g = Laplacian( CrossProduct( _x0.q, x.q ));
	g -= Curl(CrossProduct( x.q, _x0.omega ));
	return g;
}

Scalar LinearizedPeriodicIBSolver::N(const State& x) const {
	int k = x.timestep % _period;
	cout << "At time step " << x.timestep << ", phase k = " << k << endl;
	Flux v = CrossProduct( _x0periodic[k].q, x.omega );
	v += CrossProduct( x.q, _x0periodic[k].omega );
	Scalar g = Curl( v );
	return g;
}

// =========== //
// SFD methods //
// =========== //

Scalar SFDSolver::N(const State& x) const {
	Flux v = CrossProduct( x.q, x.omega );
	Scalar g = Curl( v );
	Scalar temp( x.omega );  // because x is const here...hmmm
	g -= _chi * ( temp - _xhat.omega );
	return g;
}

void SFDSolver::advanceSubstep( State& x, const Scalar& nonlinear, int i ) {
    assert( x.time == _xhat.time );

	// Initialize _xhat if necessary, save current vorticity field
	if ( _xhatSaved == false ) {
		_xhat = x;
		_xhatSaved = true;
	}
	_omegaTemp = x.omega;

	// Advance state x
	IBSolver::advanceSubstep( x, nonlinear, i );

	// Advance state _xhat
	Scalar rhs = ( _omegaTemp - _xhat.omega ) / _Delta;
	Scalar a = _scheme.an(i)*rhs;

	if ( _scheme.bn(i) != 0 ) {
		if ( _rhsSaved == false ) {
			_rhsPrev = rhs;
		}

		a += _scheme.bn(i) * _rhsPrev;
	}

	a *= _dt;
	_xhat.omega += a;

    if ( i == _scheme.nsteps()-1 ) {
        _xhat.time += _dt;
        _xhat.timestep++;
    }

	_rhsPrev = rhs;

    if( _rhsSaved == false ) {
        _rhsSaved = true;
    }
}

void SFDSolver::saveFilteredState( string outdir, string name, string numDigitInFileName ) {
    string formatString = outdir+name+numDigitInFileName+".bin"+"_xhat";
    char filename[256];
    sprintf( filename, formatString.c_str(), _xhat.timestep );
    _xhat.save( filename );
}

void SFDSolver::loadFilteredState( string icFile ) {
    string xhatFile = icFile+"_xhat";
    _xhat.omega = 0.;
    _xhat.f = 0.;
    _xhat.q = 0.;
	if (xhatFile != "_xhat") {
	    cout << "Loading initial condition from file: " << xhatFile << endl;
        if ( ! _xhat.load(xhatFile) ) {
            cout << "  (failed: setting xhat = x)" << endl;
        }
    }
    else {
        cout << "Setting xhat = x" << endl;
    }

    _xhatSaved = true;
}

} // ibpm
<commit_msg>Fixed minor bug in new IBSolver method getTimestep().  Code now compiles.<commit_after>// header file for storing integration schemes
#include "IBSolver.h"

#include "Geometry.h"
#include "ProjectionSolver.h"
#include "ConjugateGradientSolver.h"
#include "CholeskySolver.h"
#include "BoundaryVector.h"
#include "Grid.h"
#include "State.h"
#include "VectorOperations.h"
#include <string>

using namespace std;

namespace ibpm {

IBSolver::IBSolver(
	const Grid& grid,
	NavierStokesModel& model,
	double dt,
	Scheme::SchemeType scheme
	) :
	_grid( grid ),
	_scheme( scheme ),
	_name( _scheme.name( ) ),
	_dt( dt ),
	_model( model ),
	_Nprev( grid ),
	_Ntemp( grid ),
	_oldSaved( false ),
	_solver( _scheme.nsteps() ),
    _tol( 1e-7) {
		createAllSolvers();
	}

IBSolver::IBSolver(
    const Grid& grid,
    NavierStokesModel& model,
    double dt,
    Scheme::SchemeType scheme,
    double tol
    ) :
    _grid( grid ),
    _scheme( scheme ),
    _name( _scheme.name( ) ),
    _dt( dt ),
    _model( model ),
    _Nprev( grid ),
    _Ntemp( grid ),
    _oldSaved( false ),
    _solver( _scheme.nsteps() ),
    _tol( tol ) {
        createAllSolvers();
}

IBSolver::~IBSolver() {
	deleteAllSolvers();
}

string IBSolver::getName() {
	return _name;
}

double IBSolver::getTimestep() {
    return _dt;
}

void IBSolver::init() {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		_solver[i] -> init();
	}
}

void IBSolver::reset() {
    _oldSaved = false;
}

bool IBSolver::load(const string& basename) {
	bool successInit = false;
	bool successTemp = true;
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		char num[256];
		sprintf( num, "%02d", i+1 );
		string filename = basename + "_" + num;
		successTemp = _solver[i] -> load( filename ) && successTemp;
        if ( i == 0 ) {
            successInit = true;
        }
	}

	return successInit && successTemp;
}

bool IBSolver::save(const string& basename) {
	bool successInit = false;
	bool successTemp = true;
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		char num[256];
		sprintf( num, "%02d", i+1 );
		string filename = basename + "_" + num;

		successTemp = _solver[i] -> save( filename ) && successTemp;
		if ( i == 0 ) {
            successInit = true;
        }
	}

	return successInit && successTemp;
}

void IBSolver::createAllSolvers() {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		_solver[i] = createSolver( ( _scheme.an(i) + _scheme.bn(i) )*_dt );
	}
}

void IBSolver::deleteAllSolvers() {
	for (unsigned int i = 0; i < _solver.size(); i++) {
		delete _solver[i];
	}
}

ProjectionSolver* IBSolver::createSolver(double beta) {
	// Check whether all bodies are stationary
	//      If so, return a CholeskySolver
	//      If not, return a ConjugateGradientSolver
	if ( _model.isTimeDependent() ) {
		cerr << "Using ConjugateGradient solver for projection step" << endl
		<< "  tolerance = " << _tol << endl;
		return new ConjugateGradientSolver( _grid, _model, beta, _tol );
	}
	else {
		cerr << "Using Cholesky solver for projection step" << endl;
		return new CholeskySolver( _grid, _model, beta );
	}
}

void IBSolver::setTol( double tol ) {
    _tol = tol;
    createAllSolvers();
}

void IBSolver::advance( State& x ) {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		Scalar nonlinear = N(x);
		advanceSubstep( x, nonlinear, i );
	}

	x.time += _dt;
	++x.timestep;
}

void IBSolver::advance( State& x, const Scalar& Bu ) {
	for ( int i = 0; i < _scheme.nsteps(); i++ ) {
		Scalar nonlinear = N(x) + Bu;
		advanceSubstep( x, nonlinear, i );
	}

    x.time += _dt;
	++x.timestep;
}

void IBSolver::advanceSubstep( State& x, const Scalar& nonlinear, int i ) {
	// If the body is moving, update the positions of the bodies
	if ( _model.isTimeDependent() ) {
		_model.updateOperators( x.time + _scheme.cn(i) * _dt );
	}

	// Evaluate Right-Hand-Side (a) for first equation of ProjectionSolver
	Scalar a = Laplacian( x.omega );
	a *= 0.5 * _model.getAlpha() * ( _scheme.an(i) + _scheme.bn(i) );
	a += _scheme.an(i)*nonlinear;

	if ( _scheme.bn(i) != 0 ) {
        // for ab2
		if ( _oldSaved == false ) {
			_Nprev = nonlinear;
		}

		a += _scheme.bn(i) * _Nprev;
	}

	a *= _dt;
	a += x.omega;

	// Evaluate Right-Hand-Side (b) for second equation of ProjectionSolver
	BoundaryVector b = _model.getConstraints();

	// Call the ProjectionSolver to determine the vorticity and forces
	_solver[i]->solve( a, b, x.omega, x.f );

	// Update the state, for instance to compute the corresponding flux
	_model.refreshState( x );
	_Nprev = nonlinear;

    if( _oldSaved == false ) {
        _oldSaved = true;
    }
}

// ===================== //
// Derived class methods //
// ===================== //

Scalar NonlinearIBSolver::N(const State& x) const {
	Flux v = CrossProduct( x.q, x.omega );
	Scalar g = Curl( v );
	return g;
}

Scalar LinearizedIBSolver::N(const State& x) const {
	Flux v = CrossProduct( _x0.q, x.omega );
	v += CrossProduct( x.q, _x0.omega );
	Scalar g = Curl( v );
	return g;
}

Scalar AdjointIBSolver::N(const State& x) const {
    Scalar g = Laplacian( CrossProduct( _x0.q, x.q ));
	g -= Curl(CrossProduct( x.q, _x0.omega ));
	return g;
}

Scalar LinearizedPeriodicIBSolver::N(const State& x) const {
	int k = x.timestep % _period;
	cout << "At time step " << x.timestep << ", phase k = " << k << endl;
	Flux v = CrossProduct( _x0periodic[k].q, x.omega );
	v += CrossProduct( x.q, _x0periodic[k].omega );
	Scalar g = Curl( v );
	return g;
}

// =========== //
// SFD methods //
// =========== //

Scalar SFDSolver::N(const State& x) const {
	Flux v = CrossProduct( x.q, x.omega );
	Scalar g = Curl( v );
	Scalar temp( x.omega );  // because x is const here...hmmm
	g -= _chi * ( temp - _xhat.omega );
	return g;
}

void SFDSolver::advanceSubstep( State& x, const Scalar& nonlinear, int i ) {
    assert( x.time == _xhat.time );

	// Initialize _xhat if necessary, save current vorticity field
	if ( _xhatSaved == false ) {
		_xhat = x;
		_xhatSaved = true;
	}
	_omegaTemp = x.omega;

	// Advance state x
	IBSolver::advanceSubstep( x, nonlinear, i );

	// Advance state _xhat
	Scalar rhs = ( _omegaTemp - _xhat.omega ) / _Delta;
	Scalar a = _scheme.an(i)*rhs;

	if ( _scheme.bn(i) != 0 ) {
		if ( _rhsSaved == false ) {
			_rhsPrev = rhs;
		}

		a += _scheme.bn(i) * _rhsPrev;
	}

	a *= _dt;
	_xhat.omega += a;

    if ( i == _scheme.nsteps()-1 ) {
        _xhat.time += _dt;
        _xhat.timestep++;
    }

	_rhsPrev = rhs;

    if( _rhsSaved == false ) {
        _rhsSaved = true;
    }
}

void SFDSolver::saveFilteredState( string outdir, string name, string numDigitInFileName ) {
    string formatString = outdir+name+numDigitInFileName+".bin"+"_xhat";
    char filename[256];
    sprintf( filename, formatString.c_str(), _xhat.timestep );
    _xhat.save( filename );
}

void SFDSolver::loadFilteredState( string icFile ) {
    string xhatFile = icFile+"_xhat";
    _xhat.omega = 0.;
    _xhat.f = 0.;
    _xhat.q = 0.;
	if (xhatFile != "_xhat") {
	    cout << "Loading initial condition from file: " << xhatFile << endl;
        if ( ! _xhat.load(xhatFile) ) {
            cout << "  (failed: setting xhat = x)" << endl;
        }
    }
    else {
        cout << "Setting xhat = x" << endl;
    }

    _xhatSaved = true;
}

} // ibpm
<|endoftext|>


<commit_before>/* Rapicorn
 * Copyright (C) 2008 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#ifndef __RAPICORN_MODELS_HH__
#define __RAPICORN_MODELS_HH__

#include <rapicorn-core/types.hh>
#include <rapicorn-core/values.hh>

namespace Rapicorn {

/* --- Data Models --- */
class Model0 : public virtual ReferenceCountImpl { // 1*Type + 1*Value
  class Model0Value : public BaseValue {
    virtual void        changed         ();
  public:
    explicit            Model0Value     (StorageType s) : BaseValue (s) {}
  };
  Type                  m_type;
  Model0Value           m_value;
protected:
  virtual              ~Model0          (void);
  virtual void          changed         (void);
public:
  explicit              Model0          (Type t);
  Type                  type            (void)          { return m_type; }
  /* notification */
  Signal<Model0, void ()> sig_changed;
  /* accessors */
  template<typename T> void  set        (T tvalue)      { m_value.set (tvalue); }
  template<typename T> void  operator=  (T tvalue)      { m_value.set (tvalue); }
  template<typename T> T     get        ()              { return m_value.convert ((T*) 0); }
  template<typename T> /*T*/ operator T ()              { return m_value.convert ((T*) 0); }
};
typedef class Model0 Variable;

class Store1;
class Model1 : public virtual ReferenceCountImpl { // 1*Type + n*Value
  Type                  m_type;
protected:
  void                  changed         (uint64       first,
                                         uint64       count);
  void                  inserted        (uint64       first,
                                         uint64       count);
  void                  deleted         (uint64       first,
                                         uint64       count);
  virtual              ~Model1          (void);
  virtual void          handle_changed  (uint64, uint64);
  virtual void          handle_inserted (uint64, uint64);
  virtual void          handle_deleted  (uint64, uint64);
  virtual Store1*       pget_store      (void) = 0;
  virtual uint64        pcount_rows     (void) = 0;
  virtual Array         pget_row        (uint64       row) = 0;
public:
  explicit              Model1          (Type         row_type);
  Store1*               store           (void)                  { return pget_store(); }
  Type                  type            (void) const            { return m_type; }
  int64                 count           (void)                  { return pcount_rows(); }
  Array                 get             (uint64       nth)      { return pget_row (nth); }
  /* notification */
  typedef Signal<Model1, void (uint64,uint64)> RangeSignal;
  RangeSignal           sig_changed;
  RangeSignal           sig_inserted;
  RangeSignal           sig_deleted;
};

class Store1 : public virtual ReferenceCountImpl { // 1*Type + n*Value
protected:
  virtual              ~Store1          (void);
  virtual Model1&       pget_model      (void) = 0;
  virtual void          pchange_rows    (uint64       first,
                                         uint64       count,
                                         const Array *array) = 0;
  virtual void          pinsert_rows    (int64        first,
                                         uint64       count,
                                         const Array *arrays) = 0;
  virtual void          premove_rows    (uint64       first,
                                         uint64       count) = 0;
public:
  explicit              Store1          (void);
  Model1&               model           (void)                  { return pget_model(); }
  Type                  type            (void)                  { return model().type(); }
  int64                 count           (void)                  { return model().count(); }
  Array                 get             (uint64       nth)      { return model().get (nth); }
  void                  set             (uint64       nth,
                                         const Array &array)    { pchange_rows (nth, 1, &array); }
  void                  insert          (int64        nth,
                                         const Array &array)    { pinsert_rows (nth, 1, &array); }
  void                  remove          (uint64       nth)      { premove_rows (nth, 1); }
  void                  update          (uint64       nth,
                                         const Array &array)    { pchange_rows (nth, 1, &array); }
  /* premade stores */
  static Store1*        create_memory_store     (Type row_type);
};

} // Rapicorn

#endif /* __RAPICORN_MODELS_HH__ */
<commit_msg>Added clear() method to models.<commit_after>/* Rapicorn
 * Copyright (C) 2008 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#ifndef __RAPICORN_MODELS_HH__
#define __RAPICORN_MODELS_HH__

#include <rapicorn-core/types.hh>
#include <rapicorn-core/values.hh>

namespace Rapicorn {

/* --- Data Models --- */
class Model0 : public virtual ReferenceCountImpl { // 1*Type + 1*Value
  class Model0Value : public BaseValue {
    virtual void        changed         ();
  public:
    explicit            Model0Value     (StorageType s) : BaseValue (s) {}
  };
  Type                  m_type;
  Model0Value           m_value;
protected:
  virtual              ~Model0          (void);
  virtual void          changed         (void);
public:
  explicit              Model0          (Type t);
  Type                  type            (void)          { return m_type; }
  /* notification */
  Signal<Model0, void ()> sig_changed;
  /* accessors */
  template<typename T> void  set        (T tvalue)      { m_value.set (tvalue); }
  template<typename T> void  operator=  (T tvalue)      { m_value.set (tvalue); }
  template<typename T> T     get        ()              { return m_value.convert ((T*) 0); }
  template<typename T> /*T*/ operator T ()              { return m_value.convert ((T*) 0); }
};
typedef class Model0 Variable;

class Store1;
class Model1 : public virtual ReferenceCountImpl { // 1*Type + n*Value
  Type                  m_type;
protected:
  void                  changed         (uint64       first,
                                         uint64       count);
  void                  inserted        (uint64       first,
                                         uint64       count);
  void                  deleted         (uint64       first,
                                         uint64       count);
  virtual              ~Model1          (void);
  virtual void          handle_changed  (uint64, uint64);
  virtual void          handle_inserted (uint64, uint64);
  virtual void          handle_deleted  (uint64, uint64);
  virtual Store1*       pget_store      (void) = 0;
  virtual uint64        pcount_rows     (void) = 0;
  virtual Array         pget_row        (uint64       row) = 0;
public:
  explicit              Model1          (Type         row_type);
  Store1*               store           (void)                  { return pget_store(); }
  Type                  type            (void) const            { return m_type; }
  int64                 count           (void)                  { return pcount_rows(); }
  Array                 get             (uint64       nth)      { return pget_row (nth); }
  /* notification */
  typedef Signal<Model1, void (uint64,uint64)> RangeSignal;
  RangeSignal           sig_changed;
  RangeSignal           sig_inserted;
  RangeSignal           sig_deleted;
};

class Store1 : public virtual ReferenceCountImpl { // 1*Type + n*Value
protected:
  virtual              ~Store1          (void);
  virtual Model1&       pget_model      (void) = 0;
  virtual void          pchange_rows    (uint64       first,
                                         uint64       count,
                                         const Array *array) = 0;
  virtual void          pinsert_rows    (int64        first,
                                         uint64       count,
                                         const Array *arrays) = 0;
  virtual void          premove_rows    (uint64       first,
                                         uint64       count) = 0;
public:
  explicit              Store1          (void);
  Model1&               model           (void)                  { return pget_model(); }
  Type                  type            (void)                  { return model().type(); }
  int64                 count           (void)                  { return model().count(); }
  Array                 get             (uint64       nth)      { return model().get (nth); }
  void                  set             (uint64       nth,
                                         const Array &array)    { pchange_rows (nth, 1, &array); }
  void                  insert          (int64        nth,
                                         const Array &array)    { pinsert_rows (nth, 1, &array); }
  void                  remove          (uint64       nth)      { premove_rows (nth, 1); }
  void                  update          (uint64       nth,
                                         const Array &array)    { pchange_rows (nth, 1, &array); }
  void                  clear           ()                      { premove_rows (0, count()); }
  /* premade stores */
  static Store1*        create_memory_store     (Type row_type);
};

} // Rapicorn

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


<commit_before>#include "Operations.hpp"
#include "Wallet.hpp"

#include <graphene/utilities/key_conversion.hpp>

#include <fc/smart_ref_impl.hpp>

TransferOperation* OperationBuilder::transfer(ObjectId sender, ObjectId receiver, qint64 amount,
                                             ObjectId amountType, QString memo, ObjectId feeType)
{
   try {
      TransferOperation* op = new TransferOperation;
      op->setSender(sender);
      op->setReceiver(receiver);
      op->setAmount(amount);
      op->setAmountType(amountType);
      op->setMemo(memo);
      op->setFeeType(feeType);
      auto feeParameters = model.global_properties().parameters.current_fees->get<graphene::chain::transfer_operation>();
      op->setFee(op->operation().calculate_fee(feeParameters).value);
      return op;
   } catch (const fc::exception& e) {
      qDebug() << e.to_detail_string().c_str();
      return nullptr;
   }
}

QString TransferOperation::memo() const {
   if (!m_op.memo)
      return QString::null;
   if (memoIsEncrypted())
      return tr("Encrypted Memo");
   QString memo = QString::fromStdString(m_op.memo->get_message({}, {}));
   while (memo.endsWith('\0'))
      memo.chop(1);
   return memo;
}

bool TransferOperation::memoIsEncrypted() const
{
   if (!m_op.memo)
      return false;
   if (m_op.memo->message.empty())
      return false;
   if (m_op.memo->from == public_key_type() && m_op.memo->to == public_key_type())
      return false;
   return true;
}

bool TransferOperation::canEncryptMemo(Wallet* wallet, ChainDataModel* model) const
{
   if (!m_op.memo) return false;
   auto pub = model->getAccount(sender())->memoKey();
   if (!wallet->hasPrivateKey(pub)) return false;
   return graphene::utilities::wif_to_key(wallet->getPrivateKey(pub).toStdString()).valid();
}

bool TransferOperation::canDecryptMemo(Wallet* wallet, ChainDataModel* model) const
{
   if (!m_op.memo) return false;
   auto pub = model->getAccount(receiver())->memoKey();
   if (!wallet->hasPrivateKey(pub)) return false;
   return graphene::utilities::wif_to_key(wallet->getPrivateKey(pub).toStdString()).valid();
}

QString TransferOperation::decryptedMemo(Wallet* wallet, ChainDataModel* model) const
{
   fc::ecc::private_key privateKey;
   fc::ecc::public_key publicKey;

   if (canEncryptMemo(wallet, model)) {
      privateKey = *graphene::utilities::wif_to_key(wallet->getPrivateKey(model->getAccount(sender())->memoKey()).toStdString());
      publicKey = m_op.memo->to;
   } else if (canDecryptMemo(wallet, model)) {
      privateKey = *graphene::utilities::wif_to_key(wallet->getPrivateKey(model->getAccount(receiver())->memoKey()).toStdString());
      publicKey = m_op.memo->from;
   } else return QString::null;

   return QString::fromStdString(m_op.memo->get_message(privateKey, publicKey));
}

void TransferOperation::setMemo(QString memo) {
   if (memo == this->memo())
      return;
   if (!m_op.memo)
      m_op.memo = graphene::chain::memo_data();
   while (memo.size() % 32)
      memo.append('\0');
   m_op.memo->set_message({}, {}, memo.toStdString());
   Q_EMIT memoChanged();
}

void TransferOperation::encryptMemo(Wallet* wallet, ChainDataModel* model)
{
   if (!canEncryptMemo(wallet, model)) return;
   auto privateKey = graphene::utilities::wif_to_key(wallet->getPrivateKey(model->getAccount(sender())->memoKey()).toStdString());
   if (!privateKey) return;
   m_op.memo->set_message(*privateKey, public_key_type(model->getAccount(receiver())->memoKey().toStdString()), memo().toStdString());
   Q_EMIT memoChanged();
}
<commit_msg>[GUI] Fix build on Linux<commit_after>#include "Operations.hpp"
#include "Wallet.hpp"

#include <graphene/utilities/key_conversion.hpp>

#include <fc/smart_ref_impl.hpp>

TransferOperation* OperationBuilder::transfer(ObjectId sender, ObjectId receiver, qint64 amount,
                                             ObjectId amountType, QString memo, ObjectId feeType)
{
   try {
      TransferOperation* op = new TransferOperation;
      op->setSender(sender);
      op->setReceiver(receiver);
      op->setAmount(amount);
      op->setAmountType(amountType);
      op->setMemo(memo);
      op->setFeeType(feeType);
      auto feeParameters = model.global_properties().parameters.current_fees->get<graphene::chain::transfer_operation>();
      op->setFee(op->operation().calculate_fee(feeParameters).value);
      return op;
   } catch (const fc::exception& e) {
      qDebug() << e.to_detail_string().c_str();
      return nullptr;
   }
}

QString TransferOperation::memo() const {
   if (!m_op.memo)
      return QString::null;
   if (memoIsEncrypted())
      return tr("Encrypted Memo");
   QString memo = QString::fromStdString(m_op.memo->get_message({}, {}));
   while (memo.endsWith(QChar('\0')))
      memo.chop(1);
   return memo;
}

bool TransferOperation::memoIsEncrypted() const
{
   if (!m_op.memo)
      return false;
   if (m_op.memo->message.empty())
      return false;
   if (m_op.memo->from == public_key_type() && m_op.memo->to == public_key_type())
      return false;
   return true;
}

bool TransferOperation::canEncryptMemo(Wallet* wallet, ChainDataModel* model) const
{
   if (!m_op.memo) return false;
   auto pub = model->getAccount(sender())->memoKey();
   if (!wallet->hasPrivateKey(pub)) return false;
   return graphene::utilities::wif_to_key(wallet->getPrivateKey(pub).toStdString()).valid();
}

bool TransferOperation::canDecryptMemo(Wallet* wallet, ChainDataModel* model) const
{
   if (!m_op.memo) return false;
   auto pub = model->getAccount(receiver())->memoKey();
   if (!wallet->hasPrivateKey(pub)) return false;
   return graphene::utilities::wif_to_key(wallet->getPrivateKey(pub).toStdString()).valid();
}

QString TransferOperation::decryptedMemo(Wallet* wallet, ChainDataModel* model) const
{
   fc::ecc::private_key privateKey;
   fc::ecc::public_key publicKey;

   if (canEncryptMemo(wallet, model)) {
      privateKey = *graphene::utilities::wif_to_key(wallet->getPrivateKey(model->getAccount(sender())->memoKey()).toStdString());
      publicKey = m_op.memo->to;
   } else if (canDecryptMemo(wallet, model)) {
      privateKey = *graphene::utilities::wif_to_key(wallet->getPrivateKey(model->getAccount(receiver())->memoKey()).toStdString());
      publicKey = m_op.memo->from;
   } else return QString::null;

   return QString::fromStdString(m_op.memo->get_message(privateKey, publicKey));
}

void TransferOperation::setMemo(QString memo) {
   if (memo == this->memo())
      return;
   if (!m_op.memo)
      m_op.memo = graphene::chain::memo_data();
   while (memo.size() % 32)
      memo.append('\0');
   m_op.memo->set_message({}, {}, memo.toStdString());
   Q_EMIT memoChanged();
}

void TransferOperation::encryptMemo(Wallet* wallet, ChainDataModel* model)
{
   if (!canEncryptMemo(wallet, model)) return;
   auto privateKey = graphene::utilities::wif_to_key(wallet->getPrivateKey(model->getAccount(sender())->memoKey()).toStdString());
   if (!privateKey) return;
   m_op.memo->set_message(*privateKey, public_key_type(model->getAccount(receiver())->memoKey().toStdString()), memo().toStdString());
   Q_EMIT memoChanged();
}
<|endoftext|>


<commit_before>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Infomap software package is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/

#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include "utils/Logger.h"
#include "io/Config.h"
#include "infomap/InfomapContext.h"
#include "utils/Stopwatch.h"
#include "io/ProgramInterface.h"
#include "io/convert.h"
#include "utils/FileURI.h"
#include "utils/Date.h"
#include <iomanip>
#include "io/version.h"

void runInfomap(Config const& config)
{
	InfomapContext context(config);
	context.getInfomap()->run();
}

Config getConfig(int argc, char *argv[])
{
	Config conf;
	ProgramInterface api("Infomap",
			"Implementation of the Infomap clustering algorithm based on the Map Equation (see www.mapequation.org)",
			INFOMAP_VERSION);

	// --------------------- Input options ---------------------
	api.addNonOptionArgument(conf.networkFile, "network_file",
			"The file containing the network data. Accepted formats: Pajek (implied by .net) and link list (.txt)");

	api.addOptionArgument(conf.inputFormat, 'i', "input-format",
			"Specify input format ('pajek' or 'link-list') to override format possibly implied by file extension.", "s");

	api.addOptionArgument(conf.parseWithoutIOStreams, "without-iostream",
			"Parse the input network data without the iostream library. Can be a bit faster, but not as robust.");

	api.addOptionArgument(conf.zeroBasedNodeNumbers, 'z', "zero-based-numbering",
			"Assume node numbers start from zero in the input file instead of one.");

	api.addOptionArgument(conf.includeSelfLinks, 'k', "include-self-links",
			"Include links with the same source and target node. (Ignored by default.)");

	api.addOptionArgument(conf.nodeLimit, 'O', "node-limit",
			"Limit the number of nodes to read from the network. Ignore links connected to ignored nodes.", "n");

	api.addOptionArgument(conf.clusterDataFile, 'c', "cluster-data",
			"Provide an initial two-level solution (.clu format).", "p");

	// --------------------- Output options ---------------------
	api.addOptionArgument(conf.printTree, "tree",
			"Print the hierarchy in .tree format. (default true if no other output with cluster data)");

	api.addOptionArgument(conf.printMap, "map",
			"Print the top two-level modular network in the .map format.");

	api.addOptionArgument(conf.printClu, "clu",
			"Print the top cluster indices for each node.");

	api.addOptionArgument(conf.printNodeRanks, "node-ranks",
			"Print the calculated flow for each node to a file.");

	api.addOptionArgument(conf.printPajekNetwork, "pajek",
			"Print the parsed network in Pajek format.");

	api.addOptionArgument(conf.printBinaryTree, "btree",
			"Print the tree in a streamable binary format.");

	api.addOptionArgument(conf.printBinaryFlowTree, "bftree",
			"Print the tree including horizontal flow links in a streamable binary format.");

	api.addOptionArgument(conf.printFlowNetwork, "flow-network",
			"Print the network with calculated flow values.");

	api.addOptionArgument(conf.noFileOutput, '0', "no-file-output",
			"Don't print any output to file.");

	// --------------------- Core algorithm options ---------------------
	api.addOptionArgument(conf.twoLevel, '2', "two-level",
			"Optimize a two-level partition of the network.");

	bool dummyUndirected;
	api.addOptionArgument(dummyUndirected, 'u', "undirected",
			"Assume undirected links. (default)");

	api.addOptionArgument(conf.directed, 'd', "directed",
			"Assume directed links.");

	api.addOptionArgument(conf.undirdir, 't', "undirdir",
			"Two-mode dynamics: Assume undirected links for calculating flow, but directed when minimizing codelength.");

	api.addOptionArgument(conf.outdirdir, "outdirdir",
			"Two-mode dynamics: Count only ingoing links when calculating the flow, but all when minimizing codelength.");

	api.addOptionArgument(conf.rawdir, 'w', "rawdir",
			"Two-mode dynamics: Assume directed links and let the raw link weights be the flow.");

	api.addOptionArgument(conf.recordedTeleportation, 'e', "recorded-teleportation",
			"If teleportation is used to calculate the flow, also record it when minimizing codelength.");

	api.addOptionArgument(conf.teleportToNodes, 'o', "to-nodes",
			"Teleport to nodes (like the PageRank algorithm) instead of to links.");

	api.addOptionArgument(conf.teleportationProbability, 'p', "teleportation-probability",
			"The probability of teleporting to a random node or link.", "f");

	api.addOptionArgument(conf.selfTeleportationProbability, 'y', "self-link-teleportation-probability",
			"The probability of teleporting to itself. Effectively increasing the code rate, generating more and smaller modules.", "f");

	api.addOptionArgument(conf.seedToRandomNumberGenerator, 's', "seed",
			"A seed (integer) to the random number generator.", "n");

	// --------------------- Performance and accuracy options ---------------------
	api.addOptionArgument(conf.numTrials, 'N', "num-trials",
			"The number of outer-most loops to run before picking the best solution.", "n");

	api.addOptionArgument(conf.minimumCodelengthImprovement, 'm', "min-improvement",
			"Minimum codelength threshold for accepting a new solution.", "f");

	api.addOptionArgument(conf.randomizeCoreLoopLimit, 'a', "random-loop-limit",
			"Randomize the core loop limit from 1 to 'core-loop-limit'");

	api.addOptionArgument(conf.coreLoopLimit, 'M', "core-loop-limit",
			"Limit the number of loops that tries to move each node into the best possible module", "n");

	api.addOptionArgument(conf.levelAggregationLimit, 'L', "core-level-limit",
			"Limit the number of times the core loops are reapplied on existing modular network to search bigger structures.", "n");

	api.addOptionArgument(conf.tuneIterationLimit, 'T', "tune-iteration-limit",
			"Limit the number of main iterations in the two-level partition algorithm. 0 means no limit.", "n");

	api.addOptionArgument(conf.minimumRelativeTuneIterationImprovement, 'U', "tune-iteration-threshold",
			"Set a codelength improvement threshold of each new tune iteration to 'f' times the initial two-level codelength.", "f");

	api.addOptionArgument(conf.fastCoarseTunePartition, 'C', "fast-coarse-tune",
			"Try to find the quickest partition of each module when creating sub-modules for the coarse-tune part.");

	api.addOptionArgument(conf.alternateCoarseTuneLevel, 'A', "alternate-coarse-tune-level",
			"Try to find different levels of sub-modules to move in the coarse-tune part.");

	api.addOptionArgument(conf.coarseTuneLevel, 'S', "coarse-tune-level",
			"Set the recursion limit when searching for sub-modules. A level of 1 will find sub-sub-modules.", "n");

	api.addIncrementalOptionArgument(conf.fastHierarchicalSolution, 'F', "fast-hierarchical-solution",
			"Find top modules fast. Use -FF to keep all fast levels. Use -FFF to skip recursive part.");

	// --------------------- Output options ---------------------
	api.addNonOptionArgument(conf.outDirectory, "out_directory",
			"The directory to write the results to");

	api.addIncrementalOptionArgument(conf.verbosity, 'v', "verbose",
			"Verbose output on the console. Add additional 'v' flags to increase verbosity up to -vvv.");

	api.parseArgs(argc, argv);

	// Some checks
	if (*--conf.outDirectory.end() != '/')
		conf.outDirectory.append("/");

	if (!conf.haveModularResultOutput())
		conf.printTree = true;

	return conf;
}

void initBenchmark(const Config& conf, int argc, char * const argv[])
{
	std::string networkName = FileURI(conf.networkFile).getName();
	std::string logFilename = io::Str() << conf.outDirectory << networkName << ".tsv";
	Logger::setBenchmarkFilename(logFilename);
	std::ostringstream logInfo;
	logInfo << "#benchmark for";
	for (int i = 0; i < argc; ++i)
		logInfo << " " << argv[i];
	Logger::benchmark(logInfo.str(), 0, 0, 0, 0, true);
	Logger::benchmark("elapsedSeconds\ttag\tcodelength\tnumTopModules\tnumNonTrivialTopModules\ttreeDepth",
			0, 0, 0, 0, true);
	// (todo: fix problem with initializing same static file from different functions to simplify above)
	std::cout << "(Writing benchmark log to '" << logFilename << "'...)\n";
}

int run(int argc, char* argv[])
{
	Date startDate;
	Config conf;
	try
	{
		conf = getConfig(argc, argv);
		if (conf.benchmark)
			initBenchmark(conf, argc, argv);
		if (conf.verbosity == 0)
			conf.verboseNumberPrecision = 4;
		std::cout << std::setprecision(conf.verboseNumberPrecision);
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
		return 1;
	}

	std::cout << "===========================================\n";
	std::cout << "  Infomap v" << INFOMAP_VERSION << " starts at " << Date() << "\n";
	std::cout << "===========================================\n";

	runInfomap(conf);

	ASSERT(NodeBase::nodeCount() == 0); //TODO: Not working with OpenMP
//	if (NodeBase::nodeCount() != 0)
//		std::cout << "Warning: " << NodeBase::nodeCount() << " nodes not deleted!\n";

	std::cout << "===========================================\n";
	std::cout << "  Infomap ends at " << Date() << "\n";
	std::cout << "  (Elapsed time: " << (Date() - startDate) << ")\n";
	std::cout << "===========================================\n";

//	ElapsedTime t1 = (Date() - startDate);
//	std::cout << "Elapsed time: " << t1 << " (" <<
//			Stopwatch::getElapsedTimeSinceProgramStartInSec() << "s serial)." << std::endl;
	return 0;
}

int main(int argc, char* argv[])
{
	return run(argc, argv);
}
<commit_msg>Added option --no-infomap to keep initial external cluster data.<commit_after>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Infomap software package is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/

#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include "utils/Logger.h"
#include "io/Config.h"
#include "infomap/InfomapContext.h"
#include "utils/Stopwatch.h"
#include "io/ProgramInterface.h"
#include "io/convert.h"
#include "utils/FileURI.h"
#include "utils/Date.h"
#include <iomanip>
#include "io/version.h"

void runInfomap(Config const& config)
{
	InfomapContext context(config);
	context.getInfomap()->run();
}

Config getConfig(int argc, char *argv[])
{
	Config conf;
	ProgramInterface api("Infomap",
			"Implementation of the Infomap clustering algorithm based on the Map Equation (see www.mapequation.org)",
			INFOMAP_VERSION);

	// --------------------- Input options ---------------------
	api.addNonOptionArgument(conf.networkFile, "network_file",
			"The file containing the network data. Accepted formats: Pajek (implied by .net) and link list (.txt)");

	api.addOptionArgument(conf.inputFormat, 'i', "input-format",
			"Specify input format ('pajek' or 'link-list') to override format possibly implied by file extension.", "s");

	api.addOptionArgument(conf.parseWithoutIOStreams, "without-iostream",
			"Parse the input network data without the iostream library. Can be a bit faster, but not as robust.");

	api.addOptionArgument(conf.zeroBasedNodeNumbers, 'z', "zero-based-numbering",
			"Assume node numbers start from zero in the input file instead of one.");

	api.addOptionArgument(conf.includeSelfLinks, 'k', "include-self-links",
			"Include links with the same source and target node. (Ignored by default.)");

	api.addOptionArgument(conf.nodeLimit, 'O', "node-limit",
			"Limit the number of nodes to read from the network. Ignore links connected to ignored nodes.", "n");

	api.addOptionArgument(conf.clusterDataFile, 'c', "cluster-data",
			"Provide an initial two-level solution (.clu format).", "p");

	api.addOptionArgument(conf.noInfomap, "no-infomap",
			"Don't run Infomap. Useful if initial cluster data should be preserved or non-modular data printed.");

	// --------------------- Output options ---------------------
	api.addOptionArgument(conf.printTree, "tree",
			"Print the hierarchy in .tree format. (default true if no other output with cluster data)");

	api.addOptionArgument(conf.printMap, "map",
			"Print the top two-level modular network in the .map format.");

	api.addOptionArgument(conf.printClu, "clu",
			"Print the top cluster indices for each node.");

	api.addOptionArgument(conf.printNodeRanks, "node-ranks",
			"Print the calculated flow for each node to a file.");

	api.addOptionArgument(conf.printPajekNetwork, "pajek",
			"Print the parsed network in Pajek format.");

	api.addOptionArgument(conf.printBinaryTree, "btree",
			"Print the tree in a streamable binary format.");

	api.addOptionArgument(conf.printBinaryFlowTree, "bftree",
			"Print the tree including horizontal flow links in a streamable binary format.");

	api.addOptionArgument(conf.printFlowNetwork, "flow-network",
			"Print the network with calculated flow values.");

	api.addOptionArgument(conf.noFileOutput, '0', "no-file-output",
			"Don't print any output to file.");

	// --------------------- Core algorithm options ---------------------
	api.addOptionArgument(conf.twoLevel, '2', "two-level",
			"Optimize a two-level partition of the network.");

	bool dummyUndirected;
	api.addOptionArgument(dummyUndirected, 'u', "undirected",
			"Assume undirected links. (default)");

	api.addOptionArgument(conf.directed, 'd', "directed",
			"Assume directed links.");

	api.addOptionArgument(conf.undirdir, 't', "undirdir",
			"Two-mode dynamics: Assume undirected links for calculating flow, but directed when minimizing codelength.");

	api.addOptionArgument(conf.outdirdir, "outdirdir",
			"Two-mode dynamics: Count only ingoing links when calculating the flow, but all when minimizing codelength.");

	api.addOptionArgument(conf.rawdir, 'w', "rawdir",
			"Two-mode dynamics: Assume directed links and let the raw link weights be the flow.");

	api.addOptionArgument(conf.recordedTeleportation, 'e', "recorded-teleportation",
			"If teleportation is used to calculate the flow, also record it when minimizing codelength.");

	api.addOptionArgument(conf.teleportToNodes, 'o', "to-nodes",
			"Teleport to nodes (like the PageRank algorithm) instead of to links.");

	api.addOptionArgument(conf.teleportationProbability, 'p', "teleportation-probability",
			"The probability of teleporting to a random node or link.", "f");

	api.addOptionArgument(conf.selfTeleportationProbability, 'y', "self-link-teleportation-probability",
			"The probability of teleporting to itself. Effectively increasing the code rate, generating more and smaller modules.", "f");

	api.addOptionArgument(conf.seedToRandomNumberGenerator, 's', "seed",
			"A seed (integer) to the random number generator.", "n");

	// --------------------- Performance and accuracy options ---------------------
	api.addOptionArgument(conf.numTrials, 'N', "num-trials",
			"The number of outer-most loops to run before picking the best solution.", "n");

	api.addOptionArgument(conf.minimumCodelengthImprovement, 'm', "min-improvement",
			"Minimum codelength threshold for accepting a new solution.", "f");

	api.addOptionArgument(conf.randomizeCoreLoopLimit, 'a', "random-loop-limit",
			"Randomize the core loop limit from 1 to 'core-loop-limit'");

	api.addOptionArgument(conf.coreLoopLimit, 'M', "core-loop-limit",
			"Limit the number of loops that tries to move each node into the best possible module", "n");

	api.addOptionArgument(conf.levelAggregationLimit, 'L', "core-level-limit",
			"Limit the number of times the core loops are reapplied on existing modular network to search bigger structures.", "n");

	api.addOptionArgument(conf.tuneIterationLimit, 'T', "tune-iteration-limit",
			"Limit the number of main iterations in the two-level partition algorithm. 0 means no limit.", "n");

	api.addOptionArgument(conf.minimumRelativeTuneIterationImprovement, 'U', "tune-iteration-threshold",
			"Set a codelength improvement threshold of each new tune iteration to 'f' times the initial two-level codelength.", "f");

	api.addOptionArgument(conf.fastCoarseTunePartition, 'C', "fast-coarse-tune",
			"Try to find the quickest partition of each module when creating sub-modules for the coarse-tune part.");

	api.addOptionArgument(conf.alternateCoarseTuneLevel, 'A', "alternate-coarse-tune-level",
			"Try to find different levels of sub-modules to move in the coarse-tune part.");

	api.addOptionArgument(conf.coarseTuneLevel, 'S', "coarse-tune-level",
			"Set the recursion limit when searching for sub-modules. A level of 1 will find sub-sub-modules.", "n");

	api.addIncrementalOptionArgument(conf.fastHierarchicalSolution, 'F', "fast-hierarchical-solution",
			"Find top modules fast. Use -FF to keep all fast levels. Use -FFF to skip recursive part.");

	// --------------------- Output options ---------------------
	api.addNonOptionArgument(conf.outDirectory, "out_directory",
			"The directory to write the results to");

	api.addIncrementalOptionArgument(conf.verbosity, 'v', "verbose",
			"Verbose output on the console. Add additional 'v' flags to increase verbosity up to -vvv.");

	api.parseArgs(argc, argv);

	// Some checks
	if (*--conf.outDirectory.end() != '/')
		conf.outDirectory.append("/");

	if (!conf.haveModularResultOutput())
		conf.printTree = true;

	return conf;
}

void initBenchmark(const Config& conf, int argc, char * const argv[])
{
	std::string networkName = FileURI(conf.networkFile).getName();
	std::string logFilename = io::Str() << conf.outDirectory << networkName << ".tsv";
	Logger::setBenchmarkFilename(logFilename);
	std::ostringstream logInfo;
	logInfo << "#benchmark for";
	for (int i = 0; i < argc; ++i)
		logInfo << " " << argv[i];
	Logger::benchmark(logInfo.str(), 0, 0, 0, 0, true);
	Logger::benchmark("elapsedSeconds\ttag\tcodelength\tnumTopModules\tnumNonTrivialTopModules\ttreeDepth",
			0, 0, 0, 0, true);
	// (todo: fix problem with initializing same static file from different functions to simplify above)
	std::cout << "(Writing benchmark log to '" << logFilename << "'...)\n";
}

int run(int argc, char* argv[])
{
	Date startDate;
	Config conf;
	try
	{
		conf = getConfig(argc, argv);
		if (conf.benchmark)
			initBenchmark(conf, argc, argv);
		if (conf.verbosity == 0)
			conf.verboseNumberPrecision = 4;
		std::cout << std::setprecision(conf.verboseNumberPrecision);
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
		return 1;
	}

	std::cout << "===========================================\n";
	std::cout << "  Infomap v" << INFOMAP_VERSION << " starts at " << Date() << "\n";
	std::cout << "===========================================\n";

	runInfomap(conf);

	ASSERT(NodeBase::nodeCount() == 0); //TODO: Not working with OpenMP
//	if (NodeBase::nodeCount() != 0)
//		std::cout << "Warning: " << NodeBase::nodeCount() << " nodes not deleted!\n";

	std::cout << "===========================================\n";
	std::cout << "  Infomap ends at " << Date() << "\n";
	std::cout << "  (Elapsed time: " << (Date() - startDate) << ")\n";
	std::cout << "===========================================\n";

//	ElapsedTime t1 = (Date() - startDate);
//	std::cout << "Elapsed time: " << t1 << " (" <<
//			Stopwatch::getElapsedTimeSinceProgramStartInSec() << "s serial)." << std::endl;
	return 0;
}

int main(int argc, char* argv[])
{
	return run(argc, argv);
}
<|endoftext|>


<commit_before>#include "LRUCache.h"
#include <sys/time.h>
#include <math.h>

#ifndef __APPLE__
#include <unordered_map>
#endif

using namespace v8;

unsigned long getCurrentTime()
{
  timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec * 1000 + tv.tv_usec;
}

std::string getStringValue(Handle<Value> value)
{
  String::Utf8Value keyUtf8Value(value);
  return std::string(*keyUtf8Value);
}

void LRUCache::init(Handle<Object> exports)
{
  Local<String> className = String::NewSymbol("LRUCache");

  Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
  constructor->SetClassName(className);

  Handle<ObjectTemplate> instance = constructor->InstanceTemplate();
  instance->SetInternalFieldCount(6);

  Handle<ObjectTemplate> prototype = constructor->PrototypeTemplate();
  prototype->Set("get", FunctionTemplate::New(Get)->GetFunction());
  prototype->Set("set", FunctionTemplate::New(Set)->GetFunction());
  prototype->Set("remove", FunctionTemplate::New(Remove)->GetFunction());
  prototype->Set("clear", FunctionTemplate::New(Clear)->GetFunction());
  prototype->Set("size", FunctionTemplate::New(Size)->GetFunction());
  prototype->Set("stats", FunctionTemplate::New(Stats)->GetFunction());

  exports->Set(className, Persistent<Function>::New(constructor->GetFunction()));
}

Handle<Value> LRUCache::New(const Arguments& args)
{
  LRUCache* cache = new LRUCache();

  if (args.Length() > 0 && args[0]->IsObject())
  {
    Local<Object> config = args[0]->ToObject();

    Local<Value> maxElements = config->Get(String::NewSymbol("maxElements"));
    if (maxElements->IsUint32())
      cache->maxElements = maxElements->Uint32Value();

    Local<Value> maxAge = config->Get(String::NewSymbol("maxAge"));
    if (maxAge->IsUint32())
      cache->maxAge = maxAge->Uint32Value();

    Local<Value> maxLoadFactor = config->Get(String::NewSymbol("maxLoadFactor"));
    if (maxLoadFactor->IsNumber())
      cache->data.max_load_factor(maxLoadFactor->NumberValue());

    Local<Value> size = config->Get(String::NewSymbol("size"));
    if (size->IsUint32())
      cache->data.rehash(ceil(size->Uint32Value() / cache->data.max_load_factor()));
  }

  cache->Wrap(args.This());
  return args.This();
}

LRUCache::LRUCache()
{
  this->maxElements = 0;
  this->maxAge = 0;
}

LRUCache::~LRUCache()
{
  this->disposeAll();
}

void LRUCache::disposeAll()
{
  for (HashMap::iterator itr = this->data.begin(); itr != this->data.end(); itr++)
  {
    HashEntry* entry = itr->second;
    entry->value.Dispose();
    delete entry;
  }
}

void LRUCache::evict()
{
  const HashMap::iterator itr = this->data.find(this->lru.front());

  if (itr == this->data.end())
    return;

  HashEntry* entry = itr->second;

  // Dispose the V8 handle contained in the entry.
  entry->value.Dispose();

  // Remove the entry from the hash and from the LRU list.
  this->data.erase(itr);
  this->lru.pop_front();

  // Free the entry itself.
  delete entry;
}

void LRUCache::remove(const HashMap::const_iterator itr)
{
  HashEntry* entry = itr->second;

  // Dispose the V8 handle contained in the entry.
  entry->value.Dispose();

  // Remove the entry from the hash and from the LRU list.
  this->data.erase(itr);
  this->lru.erase(entry->pointer);

  // Free the entry itself.
  delete entry;
}

Handle<Value> LRUCache::Get(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  if (args.Length() != 1)
    return ThrowException(Exception::RangeError(String::New("Incorrect number of arguments for get(), expected 1")));

  std::string key = getStringValue(args[0]);
  const HashMap::const_iterator itr = cache->data.find(key);

  // If the specified entry doesn't exist, return undefined.
  if (itr == cache->data.end())
    return scope.Close(Handle<Value>());

  HashEntry* entry = itr->second;

  if (cache->maxAge > 0 && getCurrentTime() - entry->timestamp > cache->maxAge)
  {
    // The entry has passed the maximum age, so we need to remove it.
    cache->remove(itr);

    // Return undefined.
    return scope.Close(Handle<Value>());
  }
  else
  {
    // Move the value to the end of the LRU list.
    cache->lru.splice(cache->lru.end(), cache->lru, entry->pointer);

    // Return the value.
    return scope.Close(entry->value);
  }
}

Handle<Value> LRUCache::Set(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());
  unsigned long now = cache->maxAge == 0 ? 0 : getCurrentTime();

  if (args.Length() != 2)
    return ThrowException(Exception::RangeError(String::New("Incorrect number of arguments for set(), expected 2")));

  std::string key = getStringValue(args[0]);
  Local<Value> value = args[1];
  const HashMap::iterator itr = cache->data.find(key);

  if (itr == cache->data.end())
  {
    // We're adding a new item. First ensure we have space.
    if (cache->maxElements > 0 && cache->data.size() == cache->maxElements)
      cache->evict();

    // Add the value to the end of the LRU list.
    KeyList::iterator pointer = cache->lru.insert(cache->lru.end(), key);

    // Add the entry to the key-value map.
    HashEntry* entry = new HashEntry(Persistent<Value>::New(value), pointer, now);
    cache->data.insert(std::make_pair(key, entry));
  }
  else
  {
    HashEntry* entry = itr->second;

    // We're replacing an existing value, so dispose the old V8 handle to ensure it gets GC'd.
    entry->value.Dispose();

    // Replace the value in the key-value map with the new one, and update the timestamp.
    entry->value = Persistent<Value>::New(value);
    entry->timestamp = now;

    // Move the value to the end of the LRU list.
    cache->lru.splice(cache->lru.end(), cache->lru, entry->pointer);
  }

  // Return undefined.
  return scope.Close(Handle<Value>());
}

Handle<Value> LRUCache::Remove(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  if (args.Length() != 1)
    return ThrowException(Exception::RangeError(String::New("Incorrect number of arguments for remove(), expected 1")));

  std::string key = getStringValue(args[0]);
  const HashMap::iterator itr = cache->data.find(key);

  if (itr != cache->data.end())
    cache->remove(itr);

  return scope.Close(Handle<Value>());
}

Handle<Value> LRUCache::Clear(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  cache->disposeAll();
  cache->data.clear();
  cache->lru.clear();

  return scope.Close(Handle<Value>());
}

Handle<Value> LRUCache::Size(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());
  return scope.Close(Integer::New(cache->data.size()));
}

Handle<Value> LRUCache::Stats(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  Local<Object> stats = Object::New();
  stats->Set(String::NewSymbol("size"), Integer::New(cache->data.size()));
  stats->Set(String::NewSymbol("buckets"), Integer::New(cache->data.bucket_count()));
  stats->Set(String::NewSymbol("loadFactor"), Number::New(cache->data.load_factor()));
  stats->Set(String::NewSymbol("maxLoadFactor"), Number::New(cache->data.max_load_factor()));

  return scope.Close(stats);
}
<commit_msg>Hey guys, microseconds aren't milliseconds<commit_after>#include "LRUCache.h"
#include <sys/time.h>
#include <math.h>

#ifndef __APPLE__
#include <unordered_map>
#endif

using namespace v8;

unsigned long getCurrentTime()
{
  timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

std::string getStringValue(Handle<Value> value)
{
  String::Utf8Value keyUtf8Value(value);
  return std::string(*keyUtf8Value);
}

void LRUCache::init(Handle<Object> exports)
{
  Local<String> className = String::NewSymbol("LRUCache");

  Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
  constructor->SetClassName(className);

  Handle<ObjectTemplate> instance = constructor->InstanceTemplate();
  instance->SetInternalFieldCount(6);

  Handle<ObjectTemplate> prototype = constructor->PrototypeTemplate();
  prototype->Set("get", FunctionTemplate::New(Get)->GetFunction());
  prototype->Set("set", FunctionTemplate::New(Set)->GetFunction());
  prototype->Set("remove", FunctionTemplate::New(Remove)->GetFunction());
  prototype->Set("clear", FunctionTemplate::New(Clear)->GetFunction());
  prototype->Set("size", FunctionTemplate::New(Size)->GetFunction());
  prototype->Set("stats", FunctionTemplate::New(Stats)->GetFunction());

  exports->Set(className, Persistent<Function>::New(constructor->GetFunction()));
}

Handle<Value> LRUCache::New(const Arguments& args)
{
  LRUCache* cache = new LRUCache();

  if (args.Length() > 0 && args[0]->IsObject())
  {
    Local<Object> config = args[0]->ToObject();

    Local<Value> maxElements = config->Get(String::NewSymbol("maxElements"));
    if (maxElements->IsUint32())
      cache->maxElements = maxElements->Uint32Value();

    Local<Value> maxAge = config->Get(String::NewSymbol("maxAge"));
    if (maxAge->IsUint32())
      cache->maxAge = maxAge->Uint32Value();

    Local<Value> maxLoadFactor = config->Get(String::NewSymbol("maxLoadFactor"));
    if (maxLoadFactor->IsNumber())
      cache->data.max_load_factor(maxLoadFactor->NumberValue());

    Local<Value> size = config->Get(String::NewSymbol("size"));
    if (size->IsUint32())
      cache->data.rehash(ceil(size->Uint32Value() / cache->data.max_load_factor()));
  }

  cache->Wrap(args.This());
  return args.This();
}

LRUCache::LRUCache()
{
  this->maxElements = 0;
  this->maxAge = 0;
}

LRUCache::~LRUCache()
{
  this->disposeAll();
}

void LRUCache::disposeAll()
{
  for (HashMap::iterator itr = this->data.begin(); itr != this->data.end(); itr++)
  {
    HashEntry* entry = itr->second;
    entry->value.Dispose();
    delete entry;
  }
}

void LRUCache::evict()
{
  const HashMap::iterator itr = this->data.find(this->lru.front());

  if (itr == this->data.end())
    return;

  HashEntry* entry = itr->second;

  // Dispose the V8 handle contained in the entry.
  entry->value.Dispose();

  // Remove the entry from the hash and from the LRU list.
  this->data.erase(itr);
  this->lru.pop_front();

  // Free the entry itself.
  delete entry;
}

void LRUCache::remove(const HashMap::const_iterator itr)
{
  HashEntry* entry = itr->second;

  // Dispose the V8 handle contained in the entry.
  entry->value.Dispose();

  // Remove the entry from the hash and from the LRU list.
  this->data.erase(itr);
  this->lru.erase(entry->pointer);

  // Free the entry itself.
  delete entry;
}

Handle<Value> LRUCache::Get(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  if (args.Length() != 1)
    return ThrowException(Exception::RangeError(String::New("Incorrect number of arguments for get(), expected 1")));

  std::string key = getStringValue(args[0]);
  const HashMap::const_iterator itr = cache->data.find(key);

  // If the specified entry doesn't exist, return undefined.
  if (itr == cache->data.end())
    return scope.Close(Handle<Value>());

  HashEntry* entry = itr->second;

  if (cache->maxAge > 0 && getCurrentTime() - entry->timestamp > cache->maxAge)
  {
    // The entry has passed the maximum age, so we need to remove it.
    cache->remove(itr);

    // Return undefined.
    return scope.Close(Handle<Value>());
  }
  else
  {
    // Move the value to the end of the LRU list.
    cache->lru.splice(cache->lru.end(), cache->lru, entry->pointer);

    // Return the value.
    return scope.Close(entry->value);
  }
}

Handle<Value> LRUCache::Set(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());
  unsigned long now = cache->maxAge == 0 ? 0 : getCurrentTime();

  if (args.Length() != 2)
    return ThrowException(Exception::RangeError(String::New("Incorrect number of arguments for set(), expected 2")));

  std::string key = getStringValue(args[0]);
  Local<Value> value = args[1];
  const HashMap::iterator itr = cache->data.find(key);

  if (itr == cache->data.end())
  {
    // We're adding a new item. First ensure we have space.
    if (cache->maxElements > 0 && cache->data.size() == cache->maxElements)
      cache->evict();

    // Add the value to the end of the LRU list.
    KeyList::iterator pointer = cache->lru.insert(cache->lru.end(), key);

    // Add the entry to the key-value map.
    HashEntry* entry = new HashEntry(Persistent<Value>::New(value), pointer, now);
    cache->data.insert(std::make_pair(key, entry));
  }
  else
  {
    HashEntry* entry = itr->second;

    // We're replacing an existing value, so dispose the old V8 handle to ensure it gets GC'd.
    entry->value.Dispose();

    // Replace the value in the key-value map with the new one, and update the timestamp.
    entry->value = Persistent<Value>::New(value);
    entry->timestamp = now;

    // Move the value to the end of the LRU list.
    cache->lru.splice(cache->lru.end(), cache->lru, entry->pointer);
  }

  // Return undefined.
  return scope.Close(Handle<Value>());
}

Handle<Value> LRUCache::Remove(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  if (args.Length() != 1)
    return ThrowException(Exception::RangeError(String::New("Incorrect number of arguments for remove(), expected 1")));

  std::string key = getStringValue(args[0]);
  const HashMap::iterator itr = cache->data.find(key);

  if (itr != cache->data.end())
    cache->remove(itr);

  return scope.Close(Handle<Value>());
}

Handle<Value> LRUCache::Clear(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  cache->disposeAll();
  cache->data.clear();
  cache->lru.clear();

  return scope.Close(Handle<Value>());
}

Handle<Value> LRUCache::Size(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());
  return scope.Close(Integer::New(cache->data.size()));
}

Handle<Value> LRUCache::Stats(const Arguments& args)
{
  HandleScope scope;
  LRUCache* cache = ObjectWrap::Unwrap<LRUCache>(args.This());

  Local<Object> stats = Object::New();
  stats->Set(String::NewSymbol("size"), Integer::New(cache->data.size()));
  stats->Set(String::NewSymbol("buckets"), Integer::New(cache->data.bucket_count()));
  stats->Set(String::NewSymbol("loadFactor"), Number::New(cache->data.load_factor()));
  stats->Set(String::NewSymbol("maxLoadFactor"), Number::New(cache->data.max_load_factor()));

  return scope.Close(stats);
}
<|endoftext|>


<commit_before><commit_msg>ord: change write_lef multi-file to info<commit_after><|endoftext|>