<commit_before>

#include "au/ThreadManager.h"

#include "Service.h" // Own interface

namespace au
{
    namespace network
    {

        void* run_service_item( void*p )
        {
            // Recover the item from the provided pointer
            ServiceItem* item = (ServiceItem*)p;

            // Main function in Service to define what to do with new connections
            item->service->run( item->socket_connection , &item->quit );

            // Notify finish of this thread
            item->service->finish(item);

            // Remove item since it is not contained anywhere
            delete item;

            return NULL;
        }

        ServiceItem::ServiceItem( Service * _service , SocketConnection * _socket_connection )
        {
            // Keep a pointer to the service to nofity when finished
            service = _service;

            // Keep a pointer to the socket connection
            socket_connection = _socket_connection;

            // By default, do not quit
            quit = false;
        }

        ServiceItem::~ServiceItem()
        {
            // Make sure this connection is closed
            socket_connection->close();
            delete socket_connection;
        }

        void ServiceItem::stop()
        {
            socket_connection->close(); // Close connection, so the thread will come back
            quit = true;                // Also inform with this bool variable ( accessible in connection )
        }

        void ServiceItem::runInBackground()
        {
            // Run a separate thread for this connection
            pthread_t t;
            ThreadManager::shared()->addThread("ServiceItem", &t, NULL, run_service_item, this);
        }

        Service::Service( int _port ) : listener( this ) , token("Service")
        {
            port = _port;
            init = false;
        }

        Status Service::initService( )
        {
            Status s = listener.initNetworkListener( port );

            if( s == OK )
                listener.runNetworkListenerInBackground();

            return s;
        }

        std::string Service::str()
        {
            return au::str("Server on port %d" , port);
        }

        void Service::stop( bool wait )
        {
            // Stop all connections ( close socket and inform about quit )
            {
                au::TokenTaker tt(&token);
                au::set< ServiceItem >::iterator it_items;
                for (it_items = items.begin() ; it_items != items.end() ; it_items ++ )
                    (*it_items)->stop();
            }

            // Stop the main listener
            listener.stop( wait );

            // Wait until all connections are gone...
            {
                au::Cronometer c;
                while( true )
                {
                    // Check if all connections are gone
                    size_t num_items = 0;
                    {
                        au::TokenTaker tt(&token);
                        num_items = items.size();
                        if( num_items == 0 )
                            return;
                    }

                    if( c.diffTime() > 1 )
                    {
                        c.reset();
                        LM_W(("Still %lu ServiceItems do not finish after closing its associated sockets in Server %s" , num_items , str().c_str() ));
                    }

                    usleep(10000);
                }
            }
        }

        void Service::newSocketConnection( NetworkListener* _listener , SocketConnection * socket_connetion )
        {
            au::TokenTaker tt(&token);

            if( _listener != &listener )
            {
                LM_E(("Unexpected listner in au::Service"));
                return ;
            }

            // Create the item
            ServiceItem *item = new ServiceItem( this , socket_connetion );

            // Insert the item
            items.insert( item );

            // Run in background
            item->runInBackground();

        }

        au::tables::Table* Service::getConnectionsTable()
        {

            std::string format = "Host|time,f=time|In (B),f=uint64|Out (B),f=uint64|In (B/s),f=uint64|Out (B/s),f=uint64";
            au::tables::Table* table = new au::tables::Table( format );

            au::set< ServiceItem >::iterator it_items;
            for( it_items = items.begin() ; it_items != items.end() ; it_items++ )
            {
                ServiceItem * item = *it_items;

                au::StringVector values;

                values.push_back( item->socket_connection->getHostAndPort() );
                values.push_back( au::str("%lu", item->socket_connection->getTime() ) );

                values.push_back( au::str("%lu", item->socket_connection->rate_in.getTotalSize() ) );
                values.push_back( au::str("%lu", item->socket_connection->rate_out.getTotalSize() ) );
                values.push_back( au::str("%lu", item->socket_connection->rate_in.getRate() ) );
                values.push_back( au::str("%lu", item->socket_connection->rate_out.getRate() ) );

                table->addRow( values );
            }

            return table;
        }

        int Service::getPort()
        {
            return  port;
        }

        void Service::finish( ServiceItem * item )
        {
            // Mutex proctection
            au::TokenTaker tt(&token);

            // Notify this has finished
            items.erase( item );
        }

    }
}<commit_msg>Fix minor bug showing connection rates<commit_after>

#include "au/ThreadManager.h"

#include "Service.h" // Own interface

namespace au
{
    namespace network
    {

        void* run_service_item( void*p )
        {
            // Recover the item from the provided pointer
            ServiceItem* item = (ServiceItem*)p;

            // Main function in Service to define what to do with new connections
            item->service->run( item->socket_connection , &item->quit );

            // Notify finish of this thread
            item->service->finish(item);

            // Remove item since it is not contained anywhere
            delete item;

            return NULL;
        }

        ServiceItem::ServiceItem( Service * _service , SocketConnection * _socket_connection )
        {
            // Keep a pointer to the service to nofity when finished
            service = _service;

            // Keep a pointer to the socket connection
            socket_connection = _socket_connection;

            // By default, do not quit
            quit = false;
        }

        ServiceItem::~ServiceItem()
        {
            // Make sure this connection is closed
            socket_connection->close();
            delete socket_connection;
        }

        void ServiceItem::stop()
        {
            socket_connection->close(); // Close connection, so the thread will come back
            quit = true;                // Also inform with this bool variable ( accessible in connection )
        }

        void ServiceItem::runInBackground()
        {
            // Run a separate thread for this connection
            pthread_t t;
            ThreadManager::shared()->addThread("ServiceItem", &t, NULL, run_service_item, this);
        }

        Service::Service( int _port ) : listener( this ) , token("Service")
        {
            port = _port;
            init = false;
        }

        Status Service::initService( )
        {
            Status s = listener.initNetworkListener( port );

            if( s == OK )
                listener.runNetworkListenerInBackground();

            return s;
        }

        std::string Service::str()
        {
            return au::str("Server on port %d" , port);
        }

        void Service::stop( bool wait )
        {
            // Stop all connections ( close socket and inform about quit )
            {
                au::TokenTaker tt(&token);
                au::set< ServiceItem >::iterator it_items;
                for (it_items = items.begin() ; it_items != items.end() ; it_items ++ )
                    (*it_items)->stop();
            }

            // Stop the main listener
            listener.stop( wait );

            // Wait until all connections are gone...
            {
                au::Cronometer c;
                while( true )
                {
                    // Check if all connections are gone
                    size_t num_items = 0;
                    {
                        au::TokenTaker tt(&token);
                        num_items = items.size();
                        if( num_items == 0 )
                            return;
                    }

                    if( c.diffTime() > 1 )
                    {
                        c.reset();
                        LM_W(("Still %lu ServiceItems do not finish after closing its associated sockets in Server %s" , num_items , str().c_str() ));
                    }

                    usleep(10000);
                }
            }
        }

        void Service::newSocketConnection( NetworkListener* _listener , SocketConnection * socket_connetion )
        {
            au::TokenTaker tt(&token);

            if( _listener != &listener )
            {
                LM_E(("Unexpected listner in au::Service"));
                return ;
            }

            // Create the item
            ServiceItem *item = new ServiceItem( this , socket_connetion );

            // Insert the item
            items.insert( item );

            // Run in background
            item->runInBackground();

        }

        au::tables::Table* Service::getConnectionsTable()
        {

            std::string format = "Host|time,f=time|In (B),f=uint64|Out (B),f=uint64|In (B/s),f=uint64|Out (B/s),f=uint64";
            au::tables::Table* table = new au::tables::Table( format );

            au::set< ServiceItem >::iterator it_items;
            for( it_items = items.begin() ; it_items != items.end() ; it_items++ )
            {
                ServiceItem * item = *it_items;

                au::StringVector values;

                values.push_back( item->socket_connection->getHostAndPort() );
                values.push_back( au::str("%lu", item->socket_connection->getTime() ) );

                values.push_back( au::str("%lu", (size_t)item->socket_connection->rate_in.getTotalSize() ) );
                values.push_back( au::str("%lu", (size_t)item->socket_connection->rate_out.getTotalSize() ) );
                values.push_back( au::str("%lu", (size_t)item->socket_connection->rate_in.getRate() ) );
                values.push_back( au::str("%lu", (size_t)item->socket_connection->rate_out.getRate() ) );

                table->addRow( values );
            }

            return table;
        }

        int Service::getPort()
        {
            return  port;
        }

        void Service::finish( ServiceItem * item )
        {
            // Mutex proctection
            au::TokenTaker tt(&token);

            // Notify this has finished
            items.erase( item );
        }

    }
}<|endoftext|>


<commit_before>#include "Config.h"

#include <folly/Uri.h>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>

namespace rustla2 {

namespace {

constexpr char kDefaultAPI[] = "/api";
constexpr char kDefaultDBPath[] = "./overrustle.sqlite";
constexpr char kDefaultGithubURL[] =
    "https://github.com/ILiedAboutCake/Rustla2";
constexpr char kDefaultJWTSecret[] = "PepoThink";
constexpr char kDefaultJWTName[] = "jwt";
constexpr time_t kDefaultJWTTTL = 60 * 60 * 24 * 7;
constexpr uint16_t kDefaultPort = 8080;
constexpr time_t kDefaultLiveCheckInterval = 60000;
constexpr char kDefaultIPAddressHeader[] = "x-client-ip";
constexpr time_t kDefaultStreamBroadcastInterval = 60000;
constexpr time_t kDefaultRustlerBroadcastInterval = 100;
constexpr char kDefaultPublicPath[] = "./public";

}  // namespace

void Config::Init(const std::string& config_path) {
  const auto config = ReadConfigFile(config_path);

  AssignString(&api_, "API", config, kDefaultAPI);
  AssignString(&api_ws_, "API_WS", config);
  AssignString(&db_db_, "DB_DB", config);
  AssignString(&db_path_, "DB_PATH", config, kDefaultDBPath);
  AssignString(&donate_do_url_, "DONATE_DO_URL", config);
  AssignString(&donate_linode_url_, "DONATE_LINODE_URL", config);
  AssignString(&donate_paypal_url_, "DONATE_PAYPAL_URL", config);
  AssignString(&github_url_, "GITHUB_URL", config, kDefaultGithubURL);
  AssignString(&jwt_secret_, "JWT_SECRET", config, kDefaultJWTSecret);
  AssignString(&jwt_name_, "JWT_NAME", config, kDefaultJWTName);
  AssignUint(&jwt_ttl_, "JWT_TTL", config, kDefaultJWTTTL);
  AssignUint(&port_, "PORT", config, kDefaultPort);
  AssignUint(&livecheck_interval_, "LIVECHECK_INTERVAL", config,
             kDefaultLiveCheckInterval);
  AssignString(&twitch_client_id_, "TWITCH_CLIENT_ID", config);
  AssignString(&twitch_client_secret_, "TWITCH_CLIENT_SECRET", config);
  AssignString(&twitch_redirect_url_, "TWITCH_REDIRECT_URI", config);
  AssignString(&google_public_api_key_, "GOOGLE_PUBLIC_API_KEY", config);
  AssignString(&ip_address_header_, "IP_ADDRESS_HEADER", config,
               kDefaultIPAddressHeader);
  AssignUint(&stream_broadcast_interval, "STREAM_BROADCAST_INTERVAL", config,
             kDefaultStreamBroadcastInterval);
  AssignUint(&rustler_broadcast_interval, "RUSTLER_BROADCAST_INTERVAL", config,
             kDefaultRustlerBroadcastInterval);
  AssignString(&ssl_cert_path_, "SSL_CERT_PATH", config);
  AssignString(&ssl_key_path_, "SSL_KEY_PATH", config);
  AssignString(&public_path_, "PUBLIC_PATH", config, kDefaultPublicPath);

  if (!ssl_cert_path_.empty() && !ssl_key_path_.empty() &&
      !AssignString(&ssl_key_password_, "SSL_KEY_PASSWORD", config)) {
    std::cout << "Enter a password for the SSL key:" << std::endl;
    std::cin >> ssl_key_password_;
  }

  jwt_secure_ = folly::Uri(twitch_redirect_url_).scheme() == "https";
}

const std::unordered_map<std::string, std::string> Config::ReadConfigFile(
    const std::string& path) {
  std::ifstream file(path);
  std::unordered_map<std::string, std::string> config;

  std::string line;
  while (std::getline(file, line)) {
    std::istringstream line_strema(line);
    std::string key;
    if (std::getline(line_strema, key, '=')) {
      std::string value;
      if (std::getline(line_strema, value)) {
        config[key] = value;
      }
    }
  }

  return config;
}

bool Config::AssignString(
    std::string* prop, const std::string& key,
    const std::unordered_map<std::string, std::string>& config,
    const std::string fallback) {
  const char* env_value = std::getenv(key.c_str());
  if (env_value != nullptr) {
    prop->assign(env_value, strlen(env_value));
    return true;
  }

  const auto config_value = config.find(key);
  if (config_value != config.end()) {
    prop->assign(config_value->second);
    return true;
  }

  if (fallback != "") {
    prop->assign(fallback);
    return true;
  }

  return false;
}

}  // namespace rustla2
<commit_msg>print debugging information while reading config<commit_after>#include "Config.h"

#include <folly/String.h>
#include <folly/Uri.h>
#include <glog/logging.h>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>

namespace rustla2 {

namespace {

constexpr char kDefaultAPI[] = "/api";
constexpr char kDefaultDBPath[] = "./overrustle.sqlite";
constexpr char kDefaultGithubURL[] =
    "https://github.com/ILiedAboutCake/Rustla2";
constexpr char kDefaultJWTSecret[] = "PepoThink";
constexpr char kDefaultJWTName[] = "jwt";
constexpr time_t kDefaultJWTTTL = 60 * 60 * 24 * 7;
constexpr uint16_t kDefaultPort = 8080;
constexpr time_t kDefaultLiveCheckInterval = 60000;
constexpr char kDefaultIPAddressHeader[] = "x-client-ip";
constexpr time_t kDefaultStreamBroadcastInterval = 60000;
constexpr time_t kDefaultRustlerBroadcastInterval = 100;
constexpr char kDefaultPublicPath[] = "./public";

}  // namespace

void Config::Init(const std::string& config_path) {
  const auto config = ReadConfigFile(config_path);

  AssignString(&api_, "API", config, kDefaultAPI);
  AssignString(&api_ws_, "API_WS", config);
  AssignString(&db_db_, "DB_DB", config);
  AssignString(&db_path_, "DB_PATH", config, kDefaultDBPath);
  AssignString(&donate_do_url_, "DONATE_DO_URL", config);
  AssignString(&donate_linode_url_, "DONATE_LINODE_URL", config);
  AssignString(&donate_paypal_url_, "DONATE_PAYPAL_URL", config);
  AssignString(&github_url_, "GITHUB_URL", config, kDefaultGithubURL);
  AssignString(&jwt_secret_, "JWT_SECRET", config, kDefaultJWTSecret);
  AssignString(&jwt_name_, "JWT_NAME", config, kDefaultJWTName);
  AssignUint(&jwt_ttl_, "JWT_TTL", config, kDefaultJWTTTL);
  AssignUint(&port_, "PORT", config, kDefaultPort);
  AssignUint(&livecheck_interval_, "LIVECHECK_INTERVAL", config,
             kDefaultLiveCheckInterval);
  AssignString(&twitch_client_id_, "TWITCH_CLIENT_ID", config);
  AssignString(&twitch_client_secret_, "TWITCH_CLIENT_SECRET", config);
  AssignString(&twitch_redirect_url_, "TWITCH_REDIRECT_URI", config);
  AssignString(&google_public_api_key_, "GOOGLE_PUBLIC_API_KEY", config);
  AssignString(&ip_address_header_, "IP_ADDRESS_HEADER", config,
               kDefaultIPAddressHeader);
  AssignUint(&stream_broadcast_interval, "STREAM_BROADCAST_INTERVAL", config,
             kDefaultStreamBroadcastInterval);
  AssignUint(&rustler_broadcast_interval, "RUSTLER_BROADCAST_INTERVAL", config,
             kDefaultRustlerBroadcastInterval);
  AssignString(&ssl_cert_path_, "SSL_CERT_PATH", config);
  AssignString(&ssl_key_path_, "SSL_KEY_PATH", config);
  AssignString(&public_path_, "PUBLIC_PATH", config, kDefaultPublicPath);

  if (!ssl_cert_path_.empty() && !ssl_key_path_.empty() &&
      !AssignString(&ssl_key_password_, "SSL_KEY_PASSWORD", config)) {
    std::cout << "Enter a password for the SSL key:" << std::endl;
    std::cin >> ssl_key_password_;
  }

  try {
    jwt_secure_ = folly::Uri(twitch_redirect_url_).scheme() == "https";
  } catch (const std::invalid_argument& e) {
    LOG(FATAL) << "invalid TWITCH_REDIRECT_URI: " << twitch_redirect_url_;
  }
}

const std::unordered_map<std::string, std::string> Config::ReadConfigFile(
    const std::string& path) {
  LOG(INFO) << "loading config from " << path;

  std::ifstream file(path);
  std::unordered_map<std::string, std::string> config;

  std::string line;
  while (std::getline(file, line)) {
    std::istringstream line_strema(line);
    std::string key;
    if (std::getline(line_strema, key, '=')) {
      std::string value;
      if (isalnum(key[0]) && std::getline(line_strema, value)) {
        config[key] = value;
      }
    }
  }

  std::vector<std::string> config_keys;
  for (const auto& it : config) {
    config_keys.push_back(it.first);
  }
  LOG(INFO) << "loaded " << config.size() << " keys ("
            << folly::join(", ", config_keys) << ")";

  return config;
}

bool Config::AssignString(
    std::string* prop, const std::string& key,
    const std::unordered_map<std::string, std::string>& config,
    const std::string fallback) {
  const char* env_value = std::getenv(key.c_str());
  if (env_value != nullptr) {
    prop->assign(env_value, strlen(env_value));
    return true;
  }

  const auto config_value = config.find(key);
  if (config_value != config.end()) {
    prop->assign(config_value->second);
    return true;
  }

  if (fallback != "") {
    prop->assign(fallback);
    return true;
  }

  LOG(WARNING) << "no config value for " << key;

  return false;
}

}  // namespace rustla2
<|endoftext|>


<commit_before>#include <cybozu/benchmark.hpp>
#include <cybozu/option.hpp>
#include <cybozu/xorshift.hpp>
#include <mcl/fp.hpp>
#include "../src/conversion.hpp"
#include <mcl/ecparam.hpp>

typedef mcl::FpT<> Fp;
typedef mcl::FpT<mcl::ZnTag> Zn;
typedef mcl::EcT<Fp> Ec;

void benchFpSub(const char *pStr, const char *xStr, const char *yStr, mcl::fp::Mode mode)
{
	const char *s = mcl::fp::ModeToStr(mode);
	Fp::init(pStr, mode);
	Fp x(xStr);
	Fp y(yStr);

	double addT, subT, mulT, sqrT, invT;
	CYBOZU_BENCH_T(addT, Fp::add, x, x, x);
	CYBOZU_BENCH_T(subT, Fp::sub, x, x, y);
	CYBOZU_BENCH_T(mulT, Fp::mul, x, x, x);
	CYBOZU_BENCH_T(sqrT, Fp::sqr, x, x);
	CYBOZU_BENCH_T(invT, x += y;Fp::inv, x, x); // avoid same jmp
	printf("%10s bit % 3d add %8.2f sub %8.2f mul %8.2f sqr %8.2f inv %8.2f\n", s, (int)Fp::getBitSize(), addT, subT, mulT, sqrT, invT);
}

void benchFp(size_t bitSize, int mode)
{
	const struct {
		size_t bitSize;
		const char *p;
		const char *x;
		const char *y;
	} tbl[] = {
		{
			192,
			"0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d",
			"0x148094810948190412345678901234567900342423332197",
			"0x7fffffffffffffffffffffe26f2fc170f69466a74defd8d",
		},
		{
			256,
			"0x2523648240000001ba344d80000000086121000000000013a700000000000013",
			"0x1480948109481904123456789234234242423424201234567900342423332197",
			"0x151342342342341517fffffffffffffffffffffe26f2fc170f69466a74defd8d",
		},
		{
			384,
			"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
			"0x19481084109481094820948209482094820984290482212345678901234567900342308472047204720422423332197",
			"0x209348209481094820984209842094820948204204243123456789012345679003423084720472047204224233321972",

		},
		{
			521,
			"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
			"0x2908209582095820941098410948109482094820984209840294829049240294242498540975555312345678901234567900342308472047204720422423332197",
			"0x3948384209834029834092384204920349820948205872380573205782385729385729385723985837ffffffffffffffffffffffe26f2fc170f69466a74defd8d",

		},
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		if (bitSize != 0 && tbl[i].bitSize != bitSize) continue;
		if (mode & 1) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_GMP);
		if (mode & 2) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_GMP_MONT);
#ifdef MCL_USE_LLVM
		if (mode & 4) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_LLVM);
		if (mode & 8) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_LLVM_MONT);
#endif
#ifdef MCL_USE_XBYAK
		if (mode & 16) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_XBYAK);
#endif
	}
}

void benchEcSub(const mcl::EcParam& para, mcl::fp::Mode mode, mcl::ec::Mode ecMode)
{
	Fp::init(para.p, mode);
	Zn::init(para.n);
	Ec::init(para.a, para.b, ecMode);
	Fp x(para.gx);
	Fp y(para.gy);
	Ec P(x, y);
	Ec Q = P + P + P;
	double addT, subT, dblT, mulT, mulRandT;
	CYBOZU_BENCH_T(addT, Ec::add, Q, P, Q);
	CYBOZU_BENCH_T(subT, Ec::sub, Q, P, Q);
	CYBOZU_BENCH_T(dblT, Ec::dbl, P, P);
	Zn z("-3");
	CYBOZU_BENCH_T(mulT, Ec::mul, P, P, z);
	cybozu::XorShift rg;
	z.setRand(rg);
	CYBOZU_BENCH_T(mulRandT, Ec::mul, P, P, z);
	printf("%10s %10s add %8.2f sub %8.2f dbl %8.2f mul(-3) %8.2f mul(rand) %8.2f\n", para.name, mcl::fp::ModeToStr(mode), addT, subT, dblT, mulT, mulRandT);

}
void benchEc(size_t bitSize, int mode, mcl::ec::Mode ecMode)
{
	const struct mcl::EcParam tbl[] = {
		mcl::ecparam::p160_1,
		mcl::ecparam::secp160k1,
		mcl::ecparam::secp192k1,
		mcl::ecparam::NIST_P192,
		mcl::ecparam::secp224k1,
		mcl::ecparam::secp256k1,
		mcl::ecparam::NIST_P224,
		mcl::ecparam::NIST_P256,
//		mcl::ecparam::secp384r1,
		mcl::ecparam::NIST_P384,
//		mcl::ecparam::secp521r1,
		mcl::ecparam::NIST_P521,
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		if (bitSize != 0 && tbl[i].bitSize != bitSize) continue;
		benchEcSub(tbl[i], mcl::fp::FP_AUTO, ecMode);
		if (mode & 1) benchEcSub(tbl[i], mcl::fp::FP_GMP, ecMode);
		if (mode & 2) benchEcSub(tbl[i], mcl::fp::FP_GMP_MONT, ecMode);
#ifdef MCL_USE_LLVM
		if (mode & 4) benchEcSub(tbl[i], mcl::fp::FP_LLVM, ecMode);
		if (mode & 8) benchEcSub(tbl[i], mcl::fp::FP_LLVM_MONT, ecMode);
#endif
#ifdef MCL_USE_XBYAK
		if (mode & 16) benchEcSub(tbl[i], mcl::fp::FP_XBYAK, ecMode);
#endif
	}
}

void benchToStr16()
{
	puts("benchToStr16");
	const char *tbl[] = {
		"0x0",
		"0x5",
		"0x123",
		"0x123456789012345679adbc",
		"0xffffffff26f2fc170f69466a74defd8d",
		"0x100000000000000000000000000000033",
		"0x11ee12312312940000000000000000000000000002342343"
	};
	Fp::init("0xffffffffffffffffffffffffffffffffffffffffffffff13");
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		std::string str;
		Fp x(tbl[i]);
		CYBOZU_BENCH("fp::toStr16", mcl::fp::toStr16, str, x.getUnit(), x.getUnitSize(), 16);
		mpz_class y(tbl[i]);
		CYBOZU_BENCH("gmp:getStr ", mcl::gmp::getStr, str, y, 16);
	}
}

void benchFromStr16()
{
	puts("benchFromStr16");
	const char *tbl[] = {
		"0",
		"5",
		"123",
		"123456789012345679adbc",
		"ffffffff26f2fc170f69466a74defd8d",
		"100000000000000000000000000000033",
		"11ee12312312940000000000000000000000000002342343"
	};
	Fp::init("0xffffffffffffffffffffffffffffffffffffffffffffff13");
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		std::string str = tbl[i];
		Fp x;
		const size_t N = 64;
		mcl::fp::Unit buf[N];
		CYBOZU_BENCH("fp:fromStr16", mcl::fp::fromStr16, buf, N, str.c_str(), str.size());

		mpz_class y;
		CYBOZU_BENCH("gmp:setStr  ", mcl::gmp::setStr, y, str, 16);
	}
}

int main(int argc, char *argv[])
	try
{
	size_t bitSize;
	int mode;
	bool ecOnly;
	bool fpOnly;
	bool misc;
	mcl::ec::Mode ecMode;
	std::string ecModeStr;
	cybozu::Option opt;
	opt.appendOpt(&bitSize, 0, "s", ": bitSize");
	opt.appendOpt(&mode, 0, "m", ": mode(0:all, sum of 1:gmp, 2:gmp+mont, 4:llvm, 8:llvm+mont, 16:xbyak");
	opt.appendBoolOpt(&ecOnly, "ec", ": ec only");
	opt.appendBoolOpt(&fpOnly, "fp", ": fp only");
	opt.appendBoolOpt(&misc, "misc", ": other benchmark");
	opt.appendOpt(&ecModeStr, "jacobi", "ecmode", ": jacobi or proj");
	opt.appendHelp("h", ": show this message");
	if (!opt.parse(argc, argv)) {
		opt.usage();
		return 1;
	}
	if (ecModeStr == "jacobi") {
		ecMode = mcl::ec::Jacobi;
	} else if (ecModeStr == "proj") {
		ecMode = mcl::ec::Proj;
	} else {
		printf("bad ecstr %s\n", ecModeStr.c_str());
		opt.usage();
		return 1;
	}
	if (mode < 0 || mode > 31) {
		printf("bad mode %d\n", mode);
		opt.usage();
		return 1;
	}
	if (mode == 0) mode = 31;
	if (misc) {
		benchToStr16();
		benchFromStr16();
	} else {
		if (!ecOnly) benchFp(bitSize, mode);
		if (!fpOnly) {
			printf("ecMode=%s\n", ecModeStr.c_str());
			benchEc(bitSize, mode, ecMode);
		}
	}
} catch (std::exception& e) {
	printf("ERR %s\n", e.what());
}

<commit_msg>compare Ec::add and mixed Ec::add<commit_after>#include <cybozu/benchmark.hpp>
#include <cybozu/option.hpp>
#include <cybozu/xorshift.hpp>
#include <mcl/fp.hpp>
#include "../src/conversion.hpp"
#include <mcl/ecparam.hpp>

typedef mcl::FpT<> Fp;
typedef mcl::FpT<mcl::ZnTag> Zn;
typedef mcl::EcT<Fp> Ec;

void benchFpSub(const char *pStr, const char *xStr, const char *yStr, mcl::fp::Mode mode)
{
	const char *s = mcl::fp::ModeToStr(mode);
	Fp::init(pStr, mode);
	Fp x(xStr);
	Fp y(yStr);

	double addT, subT, mulT, sqrT, invT;
	CYBOZU_BENCH_T(addT, Fp::add, x, x, x);
	CYBOZU_BENCH_T(subT, Fp::sub, x, x, y);
	CYBOZU_BENCH_T(mulT, Fp::mul, x, x, x);
	CYBOZU_BENCH_T(sqrT, Fp::sqr, x, x);
	CYBOZU_BENCH_T(invT, x += y;Fp::inv, x, x); // avoid same jmp
	printf("%10s bit % 3d add %8.2f sub %8.2f mul %8.2f sqr %8.2f inv %8.2f\n", s, (int)Fp::getBitSize(), addT, subT, mulT, sqrT, invT);
}

void benchFp(size_t bitSize, int mode)
{
	const struct {
		size_t bitSize;
		const char *p;
		const char *x;
		const char *y;
	} tbl[] = {
		{
			192,
			"0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d",
			"0x148094810948190412345678901234567900342423332197",
			"0x7fffffffffffffffffffffe26f2fc170f69466a74defd8d",
		},
		{
			256,
			"0x2523648240000001ba344d80000000086121000000000013a700000000000013",
			"0x1480948109481904123456789234234242423424201234567900342423332197",
			"0x151342342342341517fffffffffffffffffffffe26f2fc170f69466a74defd8d",
		},
		{
			384,
			"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff",
			"0x19481084109481094820948209482094820984290482212345678901234567900342308472047204720422423332197",
			"0x209348209481094820984209842094820948204204243123456789012345679003423084720472047204224233321972",

		},
		{
			521,
			"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
			"0x2908209582095820941098410948109482094820984209840294829049240294242498540975555312345678901234567900342308472047204720422423332197",
			"0x3948384209834029834092384204920349820948205872380573205782385729385729385723985837ffffffffffffffffffffffe26f2fc170f69466a74defd8d",

		},
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		if (bitSize != 0 && tbl[i].bitSize != bitSize) continue;
		if (mode & 1) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_GMP);
		if (mode & 2) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_GMP_MONT);
#ifdef MCL_USE_LLVM
		if (mode & 4) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_LLVM);
		if (mode & 8) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_LLVM_MONT);
#endif
#ifdef MCL_USE_XBYAK
		if (mode & 16) benchFpSub(tbl[i].p, tbl[i].x, tbl[i].y, mcl::fp::FP_XBYAK);
#endif
	}
}

void benchEcSub(const mcl::EcParam& para, mcl::fp::Mode mode, mcl::ec::Mode ecMode)
{
	Fp::init(para.p, mode);
	Zn::init(para.n);
	Ec::init(para.a, para.b, ecMode);
	Fp x(para.gx);
	Fp y(para.gy);
	Ec P(x, y);
	Ec P2; Ec::add(P2, P, P);
	Ec Q = P + P + P;
	double addT, add2T, subT, dblT, mulT, mulRandT, normT;
	CYBOZU_BENCH_T(addT, P = P2; Ec::add, Q, P, Q);
	P.normalize();
	CYBOZU_BENCH_T(add2T, Ec::add, Q, P, Q);
	CYBOZU_BENCH_T(subT, Ec::sub, Q, P, Q);
	CYBOZU_BENCH_T(dblT, Ec::dbl, P, P);
	Zn z("-3");
	CYBOZU_BENCH_T(mulT, Ec::mul, P, P, z);
	cybozu::XorShift rg;
	z.setRand(rg);
	CYBOZU_BENCH_T(mulRandT, Ec::mul, P, P, z);
	CYBOZU_BENCH_T(normT, Q = P; Q.normalize);
	printf("%10s %10s add %8.2f add2 %8.2f sub %8.2f dbl %8.2f mul(-3) %8.2f mul(rand) %8.2f norm %8.2f\n", para.name, mcl::fp::ModeToStr(mode), addT, add2T, subT, dblT, mulT, mulRandT, normT);

}
void benchEc(size_t bitSize, int mode, mcl::ec::Mode ecMode)
{
	const struct mcl::EcParam tbl[] = {
		mcl::ecparam::p160_1,
		mcl::ecparam::secp160k1,
		mcl::ecparam::secp192k1,
		mcl::ecparam::NIST_P192,
		mcl::ecparam::secp224k1,
		mcl::ecparam::secp256k1,
		mcl::ecparam::NIST_P224,
		mcl::ecparam::NIST_P256,
//		mcl::ecparam::secp384r1,
		mcl::ecparam::NIST_P384,
//		mcl::ecparam::secp521r1,
		mcl::ecparam::NIST_P521,
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		if (bitSize != 0 && tbl[i].bitSize != bitSize) continue;
		benchEcSub(tbl[i], mcl::fp::FP_AUTO, ecMode);
		if (mode & 1) benchEcSub(tbl[i], mcl::fp::FP_GMP, ecMode);
		if (mode & 2) benchEcSub(tbl[i], mcl::fp::FP_GMP_MONT, ecMode);
#ifdef MCL_USE_LLVM
		if (mode & 4) benchEcSub(tbl[i], mcl::fp::FP_LLVM, ecMode);
		if (mode & 8) benchEcSub(tbl[i], mcl::fp::FP_LLVM_MONT, ecMode);
#endif
#ifdef MCL_USE_XBYAK
		if (mode & 16) benchEcSub(tbl[i], mcl::fp::FP_XBYAK, ecMode);
#endif
	}
}

void benchToStr16()
{
	puts("benchToStr16");
	const char *tbl[] = {
		"0x0",
		"0x5",
		"0x123",
		"0x123456789012345679adbc",
		"0xffffffff26f2fc170f69466a74defd8d",
		"0x100000000000000000000000000000033",
		"0x11ee12312312940000000000000000000000000002342343"
	};
	Fp::init("0xffffffffffffffffffffffffffffffffffffffffffffff13");
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		std::string str;
		Fp x(tbl[i]);
		CYBOZU_BENCH("fp::toStr16", mcl::fp::toStr16, str, x.getUnit(), x.getUnitSize(), 16);
		mpz_class y(tbl[i]);
		CYBOZU_BENCH("gmp:getStr ", mcl::gmp::getStr, str, y, 16);
	}
}

void benchFromStr16()
{
	puts("benchFromStr16");
	const char *tbl[] = {
		"0",
		"5",
		"123",
		"123456789012345679adbc",
		"ffffffff26f2fc170f69466a74defd8d",
		"100000000000000000000000000000033",
		"11ee12312312940000000000000000000000000002342343"
	};
	Fp::init("0xffffffffffffffffffffffffffffffffffffffffffffff13");
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		std::string str = tbl[i];
		Fp x;
		const size_t N = 64;
		mcl::fp::Unit buf[N];
		CYBOZU_BENCH("fp:fromStr16", mcl::fp::fromStr16, buf, N, str.c_str(), str.size());

		mpz_class y;
		CYBOZU_BENCH("gmp:setStr  ", mcl::gmp::setStr, y, str, 16);
	}
}

int main(int argc, char *argv[])
	try
{
	size_t bitSize;
	int mode;
	bool ecOnly;
	bool fpOnly;
	bool misc;
	mcl::ec::Mode ecMode;
	std::string ecModeStr;
	cybozu::Option opt;
	opt.appendOpt(&bitSize, 0, "s", ": bitSize");
	opt.appendOpt(&mode, 0, "m", ": mode(0:all, sum of 1:gmp, 2:gmp+mont, 4:llvm, 8:llvm+mont, 16:xbyak");
	opt.appendBoolOpt(&ecOnly, "ec", ": ec only");
	opt.appendBoolOpt(&fpOnly, "fp", ": fp only");
	opt.appendBoolOpt(&misc, "misc", ": other benchmark");
	opt.appendOpt(&ecModeStr, "jacobi", "ecmode", ": jacobi or proj");
	opt.appendHelp("h", ": show this message");
	if (!opt.parse(argc, argv)) {
		opt.usage();
		return 1;
	}
	if (ecModeStr == "jacobi") {
		ecMode = mcl::ec::Jacobi;
	} else if (ecModeStr == "proj") {
		ecMode = mcl::ec::Proj;
	} else {
		printf("bad ecstr %s\n", ecModeStr.c_str());
		opt.usage();
		return 1;
	}
	if (mode < 0 || mode > 31) {
		printf("bad mode %d\n", mode);
		opt.usage();
		return 1;
	}
	if (mode == 0) mode = 31;
	if (misc) {
		benchToStr16();
		benchFromStr16();
	} else {
		if (!ecOnly) benchFp(bitSize, mode);
		if (!fpOnly) {
			printf("ecMode=%s\n", ecModeStr.c_str());
			benchEc(bitSize, mode, ecMode);
		}
	}
} catch (std::exception& e) {
	printf("ERR %s\n", e.what());
}

<|endoftext|>


<commit_before>// linear performance checker

#include <unistd.h>
#include <sys/time.h>

#include <iostream>
#include <string>
#include <algorithm>

#include "linear/tcp_server.h"
#include "linear/tcp_client.h"
#include "linear/log.h"

#define DEFAULT_TRY_NUM (1000)
#define DEFAULT_MSIZ (128)

using namespace linear::log;

namespace receiver {

class Handler : public linear::Handler {
 public:
  Handler() : confirm_(false), running_(true) {}
  ~Handler() {}

  void OnConnect(const linear::Socket&) {
    confirm_ = true;
  }
  void OnDisconnect(const linear::Socket&, const linear::Error&) {
    confirm_ = true;
    running_ = false;
  }
  void OnMessage(const linear::Socket& socket, const linear::Message& msg) {
    switch(msg.type) {
    case linear::REQUEST:
      {
        const linear::Request& request = msg.as<linear::Request>();
        if (request.method == "echo") {
          linear::Response response(request.msgid, request.params);
          response.Send(socket);
        } else {
          linear::Response response(request.msgid, linear::type::nil(), std::string("invalid method"));
          response.Send(socket);
        }
        break;
      }
    case linear::NOTIFY:
    case linear::RESPONSE:
    default:
      {
        break;
      }
    }
  }
  bool Confirm() {
    return confirm_;
  }
  bool Running() {
    return running_;
  }

 private:
  bool confirm_;
  bool running_;
};

} // namespace receiver

namespace sender {

class Handler : public linear::Handler {
 public:
  Handler(size_t num, size_t msiz)
    : running_(true), num_(num), now_(0), msiz_(msiz), err_cnt_(0) {}
  ~Handler() {}

  void OnConnect(const linear::Socket& socket) {
    struct timeval t;
    gettimeofday(&t, NULL);
    linear::Request request("echo", std::string(msiz_, 'a'));
    linear::Error e = request.Send(socket);
    if (e.Code() != linear::LNR_OK) {
      err_cnt_++;
      running_ = false;
      return;
    }
    request_map_.insert(std::make_pair<uint32_t, struct timeval>(request.msgid, t));
    now_++;
  }
  void OnDisconnect(const linear::Socket&, const linear::Error&) {
    if (now_ == 0) {
      err_cnt_++;
    }
    running_ = false;
  }
  void OnMessage(const linear::Socket& socket, const linear::Message& msg) {
    switch(msg.type) {
    case linear::RESPONSE:
      {
        const linear::Response& response = msg.as<linear::Response>();
        struct timeval t;
        gettimeofday(&t, NULL);
        std::map<uint32_t, struct timeval>::iterator it = request_map_.find(response.msgid);
        if (it == request_map_.end()) {
          err_cnt_++;
        } else {
          struct timeval prev = (*it).second;
          uint64_t d = (t.tv_sec - prev.tv_sec) * 1000 * 1000 + (t.tv_usec - prev.tv_usec);
          duration_.push_back(d);
        }
        if (now_ >= num_) {
          running_ = false;
          return;
        }
        linear::Request request("echo", std::string(msiz_, 'a'));
        linear::Error e = request.Send(socket);
        if (e.Code() != linear::LNR_OK) {
          err_cnt_++;
          running_ = false;
          return;
        }
        request_map_.insert(std::make_pair<uint32_t, struct timeval>(request.msgid, t));
        now_++;
        break;
      }
    case linear::NOTIFY:
    case linear::REQUEST:
    default:
      {
        err_cnt_++;
        break;
      }
    }
  }
  void OnError(const linear::Socket& socket, const linear::Message&, const linear::Error&) {
    struct timeval t;
    gettimeofday(&t, NULL);
    err_cnt_++;
    if (now_ >= num_) {
      running_ = false;
      return;
    }
    linear::Request request("echo", std::string(msiz_, 'a'));
    linear::Error e = request.Send(socket);
    if (e.Code() != linear::LNR_OK) {
      err_cnt_++;
      running_ = false;
      return;
    }
    request_map_.insert(std::make_pair<uint32_t, struct timeval>(request.msgid, t));
    now_++;
  }

  bool Running() {
    return running_;
  }
  void ShowResult() {
    bool min_flag = true;
    uint64_t max = 0, min = 0, sum = 0;
    for (std::vector<uint64_t>::iterator it = duration_.begin();
         it != duration_.end(); it++) {
      if (min_flag) {
        min = *it;
        min_flag = false;
      } else {
        min = (min < *it) ? min : *it;
      }
      max = (max > *it) ? max : *it;
      sum += *it;
    }
    size_t midIndex = duration_.size() / 2;
    std::nth_element(duration_.begin(), duration_.end() + midIndex, duration_.end());
    std::cout << "--- Result ---" << std::endl;
    std::cout << "success: " << duration_.size() << ", error: " << err_cnt_
              << ", RTT => min: " << static_cast<double>(min) / 1000.0
              << "ms, max: " << static_cast<double>(max) / 1000.0
              << "ms, ave: " << static_cast<double>(sum) / static_cast<double>(num_) / 1000.0
              << "ms, med: "<< static_cast<double>(duration_[midIndex] / 1000.0) << "ms" << std::endl;
  }

 private:
  bool running_;
  size_t num_, now_;
  size_t msiz_;
  std::map<uint32_t, struct timeval> request_map_;
  std::vector<uint64_t> duration_;
  int err_cnt_;
};

} // namespace sender

void usage(char* name) {
  std::cout << "linear performance checker by using simple echo." << std::endl;
  std::cout << "run 'as a server' at first, and next run 'as a client'." << std::endl << std::endl;
  std::cout << "Usage: " << std::string(name) << " [options] [Host := 0.0.0.0] [Port := 10000]" << std::endl;
  std::cout << "[Mandatory option]" << std::endl;
  std::cout << "Please choose one from the following:" << std::endl;
  std::cout << "  -cs     : Run as a client to send a request       [  Sender  ]" << std::endl;
  std::cout << "  -cr     : Run as a client to receive a request    [ Receiver ]" << std::endl;
  std::cout << "  -ss     : Run as a server to send a request       [  Sender  ]" << std::endl;
  std::cout << "  -sr     : Run as a server to receive a request    [ Receiver ]" << std::endl;
  std::cout << "[Sender option]" << std::endl;
  std::cout << "  -m Size : Set message size.                       default := 128bytes" << std::endl;
  std::cout << "  -n Num  : Set num of try.                         default := 1000times" << std::endl;
  std::cout << "[Debug option]" << std::endl;
  std::cout << "  -l Level: Show log.                               default := off" << std::endl;
  std::cout << "            ERR = 0, WARN = 1, INFO = 2, DEBUG = 3, FULL = 4" << std::endl;
}

int main(int argc, char* argv[]) {
  typedef enum {
    UNDEFINED,
    CLIENT,
    SERVER,
  } NodeType;

  typedef enum {
    SENDER,
    RECEIVER,
  } NodeMode;

  int ch, l;
  extern char* optarg;
  extern int optind;

  char t = '\0';
  NodeType type = UNDEFINED;
  NodeMode mode = SENDER;
  size_t num = DEFAULT_TRY_NUM, msiz = DEFAULT_MSIZ;
  linear::log::Level level = linear::log::LOG_OFF;

  while ((ch = getopt(argc, argv, "c:l:m:n:s:")) != -1) {
    switch(ch) {
    case 'c':
      type = CLIENT;
      t = *optarg;
      break;
    case 'l':
      l = atoi(optarg);
      if (l >= 0) {
        level = (l < 4) ? static_cast<linear::log::Level>(l) : LOG_FULL;
      }
      break;
    case 'm':
      msiz = atoi(optarg);
      msiz = (msiz <= 0) ? DEFAULT_MSIZ : msiz;
      break;
    case 'n':
      num = atoi(optarg);
      num = (num <= 0) ? DEFAULT_TRY_NUM : num;
      break;
    case 's':
      type = SERVER;
      t = *optarg;
      break;
    default:
      usage(argv[0]);
      return -1;
    }
  }
  if (type == UNDEFINED) {
    usage(argv[0]);
    return -1;
  }
  switch(t) {
  case 's':
    mode = SENDER;
    break;
  case 'r':
    mode = RECEIVER;
    break;
  default:
    usage(argv[0]);
    return -1;
  }

  argc -= optind;
  argv += optind;

  std::string host = (argc >= 1) ? std::string(argv[0]) : "127.0.0.1";
  int port = (argc >= 2) ? atoi(argv[1]) : 10000;
  std::string tmp;

  if (level != LOG_OFF) {
    linear::log::SetLevel(level);
    linear::log::EnableStderr();
    linear::log::Colorize();
  }

  if (type == CLIENT) {
    switch(mode) {
    case RECEIVER:
      {
        linear::shared_ptr<receiver::Handler> h = linear::shared_ptr<receiver::Handler>(new receiver::Handler());
        linear::TCPClient c(h);
        linear::TCPSocket s = c.CreateSocket(host, port);
        s.Connect();
        while (!h->Confirm()) {
          usleep(10);
        }
        if (s.GetState() == linear::Socket::CONNECTED) {
          std::cout << "Run as a client to receive a request" << std::endl;
          std::cout << "--- Conditions ---" << std::endl;
          std::cout << "Target server: " << host << ":" << port << std::endl;
          while (h->Running()) {
            usleep(10);
          }
        } else {
          std::cerr << "Fail to connect to server: " << host << ":" << port << std::endl;
        }
        break;
      }
    case SENDER:
      {
        std::cout << "Run as a client to send a request" << std::endl;
        std::cout << "--- Conditions ---" << std::endl;
        std::cout << "Target: " << host << ":" << port
                  << ", Num of try: " << num << ", Message size: " << msiz << "bytes" << std::endl;
        linear::shared_ptr<sender::Handler> h = linear::shared_ptr<sender::Handler>(new sender::Handler(num, msiz));
        linear::TCPClient c(h);
        linear::TCPSocket s = c.CreateSocket(host, port);
        s.Connect();
        while (h->Running()) {
          usleep(10);
        }
        s.Disconnect();
        h->ShowResult();
        break;
      }
    default:
      assert(false);
    }
  } else if (type == SERVER) {
    switch (mode) {
    case RECEIVER:
      {
        linear::shared_ptr<receiver::Handler> h = linear::shared_ptr<receiver::Handler>(new receiver::Handler());
        linear::TCPServer s(h);
        s.Start(host, port);
        std::cout << "Run as a server to receive a request" << std::endl;
        std::cout << "--- Conditions ---" << std::endl;
        std::cout << "Server started: " << host << ":" << port << std::endl;
        while (h->Running()) {
          usleep(10);
        }
        break;
      }
    case SENDER:
      {
        std::cout << "Run as a server to send a request" << std::endl;
        std::cout << "--- Conditions ---" << std::endl;
        std::cout << "Server started: " << host << ":" << port
                  << ", Num of try: " << num << ", Message size: " << msiz << "bytes" << std::endl;
        linear::shared_ptr<sender::Handler> h = linear::shared_ptr<sender::Handler>(new sender::Handler(num, msiz));
        linear::TCPServer s(h);
        s.Start(host, port);
        while (h->Running()) {
          usleep(10);
        }
        h->ShowResult();
        break;
      }
    default:
      assert(false);
    }
  }
  return 0;
}
<commit_msg>make code clean<commit_after>// linear performance checker

#include <unistd.h>
#include <sys/time.h>

#include <iostream>
#include <string>
#include <algorithm>
#include <numeric>

#include "linear/condition_variable.h"
#include "linear/tcp_server.h"
#include "linear/tcp_client.h"
#include "linear/log.h"

#define DEFAULT_TRY_NUM (1000)
#define DEFAULT_MSIZ (128)

using namespace linear::log;

namespace receiver {

class Handler : public linear::Handler {
 public:
  Handler() {}
  ~Handler() {}

  void OnConnect(const linear::Socket&) {
    linear::unique_lock<linear::mutex> lock(mutex_);
    cv_.notify_one();
  }
  void OnDisconnect(const linear::Socket&, const linear::Error&) {
    linear::unique_lock<linear::mutex> lock(mutex_);
    cv_.notify_one();
  }
  void OnMessage(const linear::Socket& socket, const linear::Message& msg) {
    switch(msg.type) {
    case linear::REQUEST:
      {
        const linear::Request& request = msg.as<linear::Request>();
        if (request.method == "echo") {
          linear::Response response(request.msgid, request.params);
          response.Send(socket);
        } else {
          linear::Response response(request.msgid, linear::type::nil(), std::string("invalid method"));
          response.Send(socket);
        }
        break;
      }
    case linear::NOTIFY:
    case linear::RESPONSE:
    default:
      {
        break;
      }
    }
  }
  void WaitToFinish() {
    linear::unique_lock<linear::mutex> lock(mutex_);
    cv_.wait(lock);
  }

 private:
  linear::mutex mutex_;
  linear::condition_variable cv_;
};

} // namespace receiver

namespace sender {

class Handler : public linear::Handler {
 public:
  Handler(size_t num, size_t msiz) : num_(num), msiz_(msiz) {}
  ~Handler() {}

  void OnConnect(const linear::Socket& socket) {
    gettimeofday(&prev_, NULL);
    linear::Request request("echo", std::string(msiz_, 'a'));
    linear::Error e = request.Send(socket);
    if (e.Code() != linear::LNR_OK) {
      socket.Disconnect();
    }
  }
  void OnDisconnect(const linear::Socket&, const linear::Error&) {
    linear::unique_lock<linear::mutex> lock(mutex_);
    cv_.notify_one();
  }
  void OnMessage(const linear::Socket& socket, const linear::Message& msg) {
    switch(msg.type) {
    case linear::RESPONSE:
      {
        linear::Response response = msg.as<linear::Response>();
        struct timeval t;
        gettimeofday(&t, NULL);
        uint64_t d = (t.tv_sec - prev_.tv_sec) * 1000 * 1000 + (t.tv_usec - prev_.tv_usec);
        duration_.push_back(d);
        prev_ = t;
        num_--;
        if (num_ == 0) {
          socket.Disconnect();
          return;
        }
        linear::Request request("echo", std::string(msiz_, 'a'));
        linear::Error e = request.Send(socket);
        if (e.Code() != linear::LNR_OK) {
          linear::unique_lock<linear::mutex> lock(mutex_);
          cv_.notify_one();
          return;
        }
        break;
      }
    case linear::NOTIFY:
    case linear::REQUEST:
    default:
      {
        break;
      }
    }
  }
  void OnError(const linear::Socket& socket, const linear::Message&, const linear::Error&) {
    socket.Disconnect();
  }

  bool WaitToFinish() {
    linear::unique_lock<linear::mutex> lock(mutex_);
    cv_.wait(lock);
    return (num_ == 0);
  }
  void ShowResult() {
    uint64_t max = *(duration_.begin()), min = *(duration_.begin()), ave;
    for (std::vector<uint64_t>::iterator it = duration_.begin(); it != duration_.end(); it++) {
      min = (*it < min) ? *it : min;
      max = (max > *it) ? max : *it;
    }
    ave = std::accumulate(duration_.begin(), duration_.end(), 0) / duration_.size();
    size_t midIndex = duration_.size() / 2;
    std::nth_element(duration_.begin(), duration_.end() + midIndex, duration_.end());
    std::cout << "--- Result ---" << std::endl;
    std::cout << "success: " << duration_.size() << ", RTT => "
              << "min: " << min / 1000.0 << "ms, "
              << "max: " << max / 1000.0 << "ms, "
              << "ave: " << ave / 1000.0 << "ms, "
              << "med: " << duration_[midIndex] / 1000.0 << "ms" << std::endl;
  }

 private:
  size_t num_;
  size_t msiz_;
  struct timeval prev_;
  std::vector<uint64_t> duration_;
  linear::mutex mutex_;
  linear::condition_variable cv_;
};

} // namespace sender

void usage(char* name) {
  std::cout << "linear performance checker by using simple echo." << std::endl;
  std::cout << "run 'as a server' at first, and next run 'as a client'." << std::endl << std::endl;
  std::cout << "Usage: " << std::string(name) << " [options] [Host := 0.0.0.0] [Port := 10000]" << std::endl;
  std::cout << "[Mandatory option]" << std::endl;
  std::cout << "Please choose one from the following:" << std::endl;
  std::cout << "  -cs     : Run as a client to send a request       [  Sender  ]" << std::endl;
  std::cout << "  -cr     : Run as a client to receive a request    [ Receiver ]" << std::endl;
  std::cout << "  -ss     : Run as a server to send a request       [  Sender  ]" << std::endl;
  std::cout << "  -sr     : Run as a server to receive a request    [ Receiver ]" << std::endl;
  std::cout << "[Sender option]" << std::endl;
  std::cout << "  -m Size : Set message size.                       default := 128bytes" << std::endl;
  std::cout << "  -n Num  : Set num of try.                         default := 1000times" << std::endl;
  std::cout << "[Debug option]" << std::endl;
  std::cout << "  -l Level: Show log.                               default := off" << std::endl;
  std::cout << "            ERR = 0, WARN = 1, INFO = 2, DEBUG = 3, FULL = 4" << std::endl;
}

int main(int argc, char* argv[]) {
  typedef enum {
    UNDEFINED,
    CLIENT,
    SERVER,
  } NodeType;

  typedef enum {
    SENDER,
    RECEIVER,
  } NodeMode;

  int ch, l;
  extern char* optarg;
  extern int optind;

  char t = '\0';
  NodeType type = UNDEFINED;
  NodeMode mode = SENDER;
  size_t num = DEFAULT_TRY_NUM, msiz = DEFAULT_MSIZ;
  linear::log::Level level = linear::log::LOG_OFF;

  while ((ch = getopt(argc, argv, "c:l:m:n:s:")) != -1) {
    switch(ch) {
    case 'c':
      type = CLIENT;
      t = *optarg;
      break;
    case 'l':
      l = atoi(optarg);
      if (l >= 0) {
        level = (l < 4) ? static_cast<linear::log::Level>(l) : LOG_FULL;
      }
      break;
    case 'm':
      msiz = atoi(optarg);
      msiz = (msiz <= 0) ? DEFAULT_MSIZ : msiz;
      break;
    case 'n':
      num = atoi(optarg);
      num = (num <= 0) ? DEFAULT_TRY_NUM : num;
      break;
    case 's':
      type = SERVER;
      t = *optarg;
      break;
    default:
      usage(argv[0]);
      return -1;
    }
  }
  if (type == UNDEFINED) {
    usage(argv[0]);
    return -1;
  }
  switch(t) {
  case 's':
    mode = SENDER;
    break;
  case 'r':
    mode = RECEIVER;
    break;
  default:
    usage(argv[0]);
    return -1;
  }

  argc -= optind;
  argv += optind;

  std::string host = (argc >= 1) ? std::string(argv[0]) : "127.0.0.1";
  int port = (argc >= 2) ? atoi(argv[1]) : 10000;
  std::string tmp;

  if (level != LOG_OFF) {
    linear::log::SetLevel(level);
    linear::log::EnableStderr();
  }

  if (type == CLIENT) {
    switch(mode) {
    case RECEIVER:
      {
        linear::shared_ptr<receiver::Handler> h = linear::shared_ptr<receiver::Handler>(new receiver::Handler());
        linear::TCPClient c(h);
        linear::TCPSocket s = c.CreateSocket(host, port);
        s.Connect();
        h->WaitToFinish();
        if (s.GetState() == linear::Socket::CONNECTED) {
          std::cout << "Run as a client to receive a request" << std::endl;
          std::cout << "--- Conditions ---" << std::endl;
          std::cout << "Target server: " << host << ":" << port << std::endl;
          h->WaitToFinish();
        } else {
          std::cerr << "perf fail" << std::endl;
        }
        break;
      }
    case SENDER:
      {
        std::cout << "Run as a client to send a request" << std::endl;
        std::cout << "--- Conditions ---" << std::endl;
        std::cout << "Target: " << host << ":" << port
                  << ", Num of try: " << num << ", Message size: " << msiz << "bytes" << std::endl;
        linear::shared_ptr<sender::Handler> h = linear::shared_ptr<sender::Handler>(new sender::Handler(num, msiz));
        linear::TCPClient c(h);
        linear::TCPSocket s = c.CreateSocket(host, port);
        s.Connect();
        if (h->WaitToFinish()) {
          h->ShowResult();
        } else {
          std::cerr << "perf fail" << std::endl;
        }
        break;
      }
    default:
      assert(false);
    }
  } else if (type == SERVER) {
    switch (mode) {
    case RECEIVER:
      {
        linear::shared_ptr<receiver::Handler> h = linear::shared_ptr<receiver::Handler>(new receiver::Handler());
        linear::TCPServer s(h);
        s.Start(host, port);
        std::cout << "Run as a server to receive a request" << std::endl;
        std::cout << "--- Conditions ---" << std::endl;
        std::cout << "Server started: " << host << ":" << port << std::endl;
        h->WaitToFinish();
        h->WaitToFinish();
        break;
      }
    case SENDER:
      {
        std::cout << "Run as a server to send a request" << std::endl;
        std::cout << "--- Conditions ---" << std::endl;
        std::cout << "Server started: " << host << ":" << port
                  << ", Num of try: " << num << ", Message size: " << msiz << "bytes" << std::endl;
        linear::shared_ptr<sender::Handler> h = linear::shared_ptr<sender::Handler>(new sender::Handler(num, msiz));
        linear::TCPServer s(h);
        s.Start(host, port);
        if (h->WaitToFinish()) {
          h->ShowResult();
        } else {
          std::cerr << "perf fail" << std::endl;
        }
        break;
      }
    default:
      assert(false);
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>// @(#)root/pyroot:$Name:  $:$Id: Executors.cxx,v 1.7 2005/06/12 17:21:53 brun Exp $
// Author: Wim Lavrijsen, Jan 2005

// Bindings
#include "PyROOT.h"
#include "Executors.h"
#include "ObjectProxy.h"
#include "PyBufferFactory.h"
#include "RootWrapper.h"

// ROOT
#include "Rtypes.h"
#include "TClass.h"
#include "DllImport.h"

// CINT
#include "Api.h"

// Standard
#include <utility>

//- data ______________________________________________________________________
PyROOT::ExecFactories_t PyROOT::gExecFactories;

//- executors for built-ins ---------------------------------------------------
PyObject* PyROOT::CharExecutor::Execute( G__CallFunc* func, void* self )
{
   long result = func->ExecInt( self );
   char c[2]; c[1] = '\0';
   c[0] = (char) result;
   return PyString_FromString( c );
}

//____________________________________________________________________________
PyObject* PyROOT::IntExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyInt_FromLong( (long)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::LongExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromLong( (long)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::ULongExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromUnsignedLong( (unsigned long)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::DoubleExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyFloat_FromDouble( (double)func->ExecDouble( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::VoidExecutor::Execute( G__CallFunc* func, void* self )
{
   func->Exec( self );
   Py_INCREF( Py_None );
   return Py_None;
}

//____________________________________________________________________________
PyObject* PyROOT::LongLongExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromLongLong( (Long64_t)G__Longlong( func->Execute( self ) ) );
}

//____________________________________________________________________________
PyObject* PyROOT::CStringExecutor::Execute( G__CallFunc* func, void* self )
{
   char* result = (char*)func->ExecInt( self );
   if ( ! result )
      return PyString_FromString( "" );

   return PyString_FromString( result );
}

//- pointer/array executors ---------------------------------------------------
PyObject* PyROOT::VoidArrayExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromVoidPtr( (void*)func->ExecInt( self ) );
}

//____________________________________________________________________________
#define PYROOT_IMPLEMENT_ARRAY_EXECUTOR( name, type )                        \
PyObject* PyROOT::name##ArrayExecutor::Execute( G__CallFunc* func, void* self )\
{                                                                            \
   return BufFac_t::Instance()->PyBuffer_FromMemory( (type*)func->ExecInt( self ) );\
}

PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Short,  Short_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( UShort, UShort_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Int,    Int_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( UInt,   UInt_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Long,   Long_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( ULong,  ULong_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Float,  Float_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Double, Double_t )

//- special cases ------------------------------------------------------------
PyObject* PyROOT::STLStringExecutor::Execute( G__CallFunc* func, void* self )
{
   std::string* result = (std::string*)func->ExecInt( self );
   if ( ! result )
      return PyString_FromString( "" );

   return PyString_FromString( (*result).c_str() );
}

//____________________________________________________________________________
PyObject* PyROOT::TGlobalExecutor::Execute( G__CallFunc* func, void* self )
{
   return BindRootGlobal( (TGlobal*)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::RootObjectExecutor::Execute( G__CallFunc* func, void* self )
{
   return BindRootObject( (void*)func->ExecInt( self ), fClass );
}

//____________________________________________________________________________
PyObject* PyROOT::RootObjectByValueExecutor::Execute( G__CallFunc* func, void* self )
{
// execution will bring a temporary in existence ...
   void* result1 = (void*)func->ExecInt( self );
   if ( ! result1 )
      return 0;

// ... which must be copied to retain ownership, then released
   void* result2 = result1;
   if ( fClass->GetClassInfo() && fClass->GetClassInfo()->Linkage() != -1 ) {
      result2 = new char[ fClass->Size() ];
      mempcpy( result2, result1, fClass->Size() );
   }
   G__pop_tempobject();            // doesn't call dtor

// the final result can then be bound
   ObjectProxy* pyobj = (ObjectProxy*)BindRootObject( result2, fClass );
   if ( ! pyobj )
      return 0;

// let python ref counting will now control the object life span
   pyobj->fFlags |= ObjectProxy::kIsOwner;
   return (PyObject*)pyobj;
}

//____________________________________________________________________________
PyObject* PyROOT::ConstructorExecutor::Execute( G__CallFunc* func, void* klass )
{
// package return address in PyObject* for caller to handle appropriately
   return (PyObject*)func->ExecInt( klass );
}

//- factories -----------------------------------------------------------------
#define PYROOT_EXECUTOR_FACTORY( name )                \
Executor* Create##name()                               \
{                                                      \
   return new name ();                                 \
}

namespace {

   using namespace PyROOT;

// us macro rather than template for portability ...
   PYROOT_EXECUTOR_FACTORY( CharExecutor )
   PYROOT_EXECUTOR_FACTORY( IntExecutor )
   PYROOT_EXECUTOR_FACTORY( LongExecutor )
   PYROOT_EXECUTOR_FACTORY( ULongExecutor )
   PYROOT_EXECUTOR_FACTORY( DoubleExecutor )
   PYROOT_EXECUTOR_FACTORY( VoidExecutor )
   PYROOT_EXECUTOR_FACTORY( LongLongExecutor )
   PYROOT_EXECUTOR_FACTORY( CStringExecutor )
   PYROOT_EXECUTOR_FACTORY( VoidArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( ShortArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( UShortArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( IntArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( UIntArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( LongArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( ULongArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( FloatArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( DoubleArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( STLStringExecutor )
   PYROOT_EXECUTOR_FACTORY( TGlobalExecutor )
   PYROOT_EXECUTOR_FACTORY( ConstructorExecutor )

// executor factories for ROOT types
   typedef std::pair< const char*, ExecutorFactory_t > ncp_t;

   ncp_t factories_[] = {
   // factories for built-ins
      ncp_t( "char",               &CreateCharExecutor                ),
      ncp_t( "unsigned char",      &CreateCharExecutor                ),
      ncp_t( "short",              &CreateIntExecutor                 ),
      ncp_t( "unsigned short",     &CreateIntExecutor                 ),
      ncp_t( "int",                &CreateIntExecutor                 ),
      ncp_t( "unsigned int",       &CreateULongExecutor               ),
      ncp_t( "UInt_t", /* enum */  &CreateULongExecutor               ),
      ncp_t( "long",               &CreateLongExecutor                ),
      ncp_t( "unsigned long",      &CreateULongExecutor               ),
      ncp_t( "long long",          &CreateLongLongExecutor            ),
      ncp_t( "float",              &CreateDoubleExecutor              ),
      ncp_t( "double",             &CreateDoubleExecutor              ),
      ncp_t( "void",               &CreateVoidExecutor                ),
      ncp_t( "bool",               &CreateIntExecutor                 ),
      ncp_t( "const char*",        &CreateCStringExecutor             ),
      ncp_t( "char*",              &CreateCStringExecutor             ),

   // pointer/array factories
      ncp_t( "void*",              &CreateVoidArrayExecutor           ),
      ncp_t( "short*",             &CreateShortArrayExecutor          ),
      ncp_t( "unsigned short*",    &CreateUShortArrayExecutor         ),
      ncp_t( "int*",               &CreateIntArrayExecutor            ),
      ncp_t( "unsigned int*",      &CreateUIntArrayExecutor           ),
      ncp_t( "long*",              &CreateLongArrayExecutor           ),
      ncp_t( "unsigned long*",     &CreateULongArrayExecutor          ),
      ncp_t( "float*",             &CreateFloatArrayExecutor          ),
      ncp_t( "double*",            &CreateDoubleArrayExecutor         ),

   // factories for special cases
      ncp_t( "std::string",        &CreateSTLStringExecutor           ),
      ncp_t( "TGlobal*",           &CreateTGlobalExecutor             ),
      ncp_t( "__init__",           &CreateConstructorExecutor         )
   };

   const int nFactories_ = sizeof( factories_ ) / sizeof( factories_[ 0 ] );

   class InitExecFactories_ {
   public:
      InitExecFactories_()
      {
         for ( int i = 0; i < nFactories_; ++i ) {
            gExecFactories[ factories_[ i ].first ] = factories_[ i ].second;
         }
      }
   } initExecvFactories_;

} // unnamed namespace
<commit_msg>replace call to mempcpy by memcpy<commit_after>// @(#)root/pyroot:$Name:  $:$Id: Executors.cxx,v 1.8 2005/06/14 05:06:03 brun Exp $
// Author: Wim Lavrijsen, Jan 2005

// Bindings
#include "PyROOT.h"
#include "Executors.h"
#include "ObjectProxy.h"
#include "PyBufferFactory.h"
#include "RootWrapper.h"

// ROOT
#include "Rtypes.h"
#include "TClass.h"
#include "DllImport.h"

// CINT
#include "Api.h"

// Standard
#include <utility>

//- data ______________________________________________________________________
PyROOT::ExecFactories_t PyROOT::gExecFactories;

//- executors for built-ins ---------------------------------------------------
PyObject* PyROOT::CharExecutor::Execute( G__CallFunc* func, void* self )
{
   long result = func->ExecInt( self );
   char c[2]; c[1] = '\0';
   c[0] = (char) result;
   return PyString_FromString( c );
}

//____________________________________________________________________________
PyObject* PyROOT::IntExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyInt_FromLong( (long)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::LongExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromLong( (long)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::ULongExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromUnsignedLong( (unsigned long)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::DoubleExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyFloat_FromDouble( (double)func->ExecDouble( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::VoidExecutor::Execute( G__CallFunc* func, void* self )
{
   func->Exec( self );
   Py_INCREF( Py_None );
   return Py_None;
}

//____________________________________________________________________________
PyObject* PyROOT::LongLongExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromLongLong( (Long64_t)G__Longlong( func->Execute( self ) ) );
}

//____________________________________________________________________________
PyObject* PyROOT::CStringExecutor::Execute( G__CallFunc* func, void* self )
{
   char* result = (char*)func->ExecInt( self );
   if ( ! result )
      return PyString_FromString( "" );

   return PyString_FromString( result );
}

//- pointer/array executors ---------------------------------------------------
PyObject* PyROOT::VoidArrayExecutor::Execute( G__CallFunc* func, void* self )
{
   return PyLong_FromVoidPtr( (void*)func->ExecInt( self ) );
}

//____________________________________________________________________________
#define PYROOT_IMPLEMENT_ARRAY_EXECUTOR( name, type )                        \
PyObject* PyROOT::name##ArrayExecutor::Execute( G__CallFunc* func, void* self )\
{                                                                            \
   return BufFac_t::Instance()->PyBuffer_FromMemory( (type*)func->ExecInt( self ) );\
}

PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Short,  Short_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( UShort, UShort_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Int,    Int_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( UInt,   UInt_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Long,   Long_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( ULong,  ULong_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Float,  Float_t )
PYROOT_IMPLEMENT_ARRAY_EXECUTOR( Double, Double_t )

//- special cases ------------------------------------------------------------
PyObject* PyROOT::STLStringExecutor::Execute( G__CallFunc* func, void* self )
{
   std::string* result = (std::string*)func->ExecInt( self );
   if ( ! result )
      return PyString_FromString( "" );

   return PyString_FromString( (*result).c_str() );
}

//____________________________________________________________________________
PyObject* PyROOT::TGlobalExecutor::Execute( G__CallFunc* func, void* self )
{
   return BindRootGlobal( (TGlobal*)func->ExecInt( self ) );
}

//____________________________________________________________________________
PyObject* PyROOT::RootObjectExecutor::Execute( G__CallFunc* func, void* self )
{
   return BindRootObject( (void*)func->ExecInt( self ), fClass );
}

//____________________________________________________________________________
PyObject* PyROOT::RootObjectByValueExecutor::Execute( G__CallFunc* func, void* self )
{
// execution will bring a temporary in existence ...
   void* result1 = (void*)func->ExecInt( self );
   if ( ! result1 )
      return 0;

// ... which must be copied to retain ownership, then released
   void* result2 = result1;
   if ( fClass->GetClassInfo() && fClass->GetClassInfo()->Linkage() != -1 ) {
      result2 = new char[ fClass->Size() ];
      memcpy( result2, result1, fClass->Size() );
   }
   G__pop_tempobject();            // doesn't call dtor

// the final result can then be bound
   ObjectProxy* pyobj = (ObjectProxy*)BindRootObject( result2, fClass );
   if ( ! pyobj )
      return 0;

// let python ref counting will now control the object life span
   pyobj->fFlags |= ObjectProxy::kIsOwner;
   return (PyObject*)pyobj;
}

//____________________________________________________________________________
PyObject* PyROOT::ConstructorExecutor::Execute( G__CallFunc* func, void* klass )
{
// package return address in PyObject* for caller to handle appropriately
   return (PyObject*)func->ExecInt( klass );
}

//- factories -----------------------------------------------------------------
#define PYROOT_EXECUTOR_FACTORY( name )                \
Executor* Create##name()                               \
{                                                      \
   return new name ();                                 \
}

namespace {

   using namespace PyROOT;

// us macro rather than template for portability ...
   PYROOT_EXECUTOR_FACTORY( CharExecutor )
   PYROOT_EXECUTOR_FACTORY( IntExecutor )
   PYROOT_EXECUTOR_FACTORY( LongExecutor )
   PYROOT_EXECUTOR_FACTORY( ULongExecutor )
   PYROOT_EXECUTOR_FACTORY( DoubleExecutor )
   PYROOT_EXECUTOR_FACTORY( VoidExecutor )
   PYROOT_EXECUTOR_FACTORY( LongLongExecutor )
   PYROOT_EXECUTOR_FACTORY( CStringExecutor )
   PYROOT_EXECUTOR_FACTORY( VoidArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( ShortArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( UShortArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( IntArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( UIntArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( LongArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( ULongArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( FloatArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( DoubleArrayExecutor )
   PYROOT_EXECUTOR_FACTORY( STLStringExecutor )
   PYROOT_EXECUTOR_FACTORY( TGlobalExecutor )
   PYROOT_EXECUTOR_FACTORY( ConstructorExecutor )

// executor factories for ROOT types
   typedef std::pair< const char*, ExecutorFactory_t > ncp_t;

   ncp_t factories_[] = {
   // factories for built-ins
      ncp_t( "char",               &CreateCharExecutor                ),
      ncp_t( "unsigned char",      &CreateCharExecutor                ),
      ncp_t( "short",              &CreateIntExecutor                 ),
      ncp_t( "unsigned short",     &CreateIntExecutor                 ),
      ncp_t( "int",                &CreateIntExecutor                 ),
      ncp_t( "unsigned int",       &CreateULongExecutor               ),
      ncp_t( "UInt_t", /* enum */  &CreateULongExecutor               ),
      ncp_t( "long",               &CreateLongExecutor                ),
      ncp_t( "unsigned long",      &CreateULongExecutor               ),
      ncp_t( "long long",          &CreateLongLongExecutor            ),
      ncp_t( "float",              &CreateDoubleExecutor              ),
      ncp_t( "double",             &CreateDoubleExecutor              ),
      ncp_t( "void",               &CreateVoidExecutor                ),
      ncp_t( "bool",               &CreateIntExecutor                 ),
      ncp_t( "const char*",        &CreateCStringExecutor             ),
      ncp_t( "char*",              &CreateCStringExecutor             ),

   // pointer/array factories
      ncp_t( "void*",              &CreateVoidArrayExecutor           ),
      ncp_t( "short*",             &CreateShortArrayExecutor          ),
      ncp_t( "unsigned short*",    &CreateUShortArrayExecutor         ),
      ncp_t( "int*",               &CreateIntArrayExecutor            ),
      ncp_t( "unsigned int*",      &CreateUIntArrayExecutor           ),
      ncp_t( "long*",              &CreateLongArrayExecutor           ),
      ncp_t( "unsigned long*",     &CreateULongArrayExecutor          ),
      ncp_t( "float*",             &CreateFloatArrayExecutor          ),
      ncp_t( "double*",            &CreateDoubleArrayExecutor         ),

   // factories for special cases
      ncp_t( "std::string",        &CreateSTLStringExecutor           ),
      ncp_t( "TGlobal*",           &CreateTGlobalExecutor             ),
      ncp_t( "__init__",           &CreateConstructorExecutor         )
   };

   const int nFactories_ = sizeof( factories_ ) / sizeof( factories_[ 0 ] );

   class InitExecFactories_ {
   public:
      InitExecFactories_()
      {
         for ( int i = 0; i < nFactories_; ++i ) {
            gExecFactories[ factories_[ i ].first ] = factories_[ i ].second;
         }
      }
   } initExecvFactories_;

} // unnamed namespace
<|endoftext|>


<commit_before>/*
 * $Id$
 *
 * Copyright(C) 1998-2004 Satoshi Nakamura
 * All rights reserved.
 *
 */

#ifndef __QSMIME_INL__
#define __QSMIME_INL__

/****************************************************************************
 *
 * FieldParserUtil
 *
 */

template<class String>
qs::basic_string_ptr<String> qs::FieldParserUtil<String>::getQString(const Char* psz,
																	 size_t nLen)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);

	StringBuffer<String> buf(nLen + 2);
	buf.append(Char('\"'));
	for (const Char* p = psz; p < psz + nLen; ++p) {
		if (*p == Char('\\') || *p == Char('\"'))
			buf.append(Char('\\'));
		buf.append(*p);
	}
	buf.append(Char('\"'));

	return buf.getString();
}

template<class String>
qs::basic_string_ptr<String> qs::FieldParserUtil<String>::getAtomOrQString(const Char* psz,
																		   size_t nLen)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);

	if (isNeedQuote(psz, nLen, true))
		return getQString(psz, nLen);
	else
		return StringTraits<String>::allocString(psz, nLen);
}

template<class String>
qs::basic_string_ptr<String> qs::FieldParserUtil<String>::getAtomsOrQString(const Char* psz,
																			size_t nLen)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);

	if (isNeedQuote(psz, nLen, false))
		return getQString(psz, nLen);
	else
		return StringTraits<String>::allocString(psz, nLen);
}

template<class String>
bool qs::FieldParserUtil<String>::isNeedQuote(const Char* psz,
											  size_t nLen,
											  bool bQuoteWhitespace)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);
	if (nLen == 0)
		return true;

	const Char* p = psz;
	while (p < psz + nLen) {
		if (unsigned char(*p) < 0x80) {
			if (FieldParser::isSpecial(char(*p)) ||
				(bQuoteWhitespace && (*p == Char(' ') || *p == Char('\t'))))
				break;
		}
		++p;
	}
	return p != psz + nLen;
}

/****************************************************************************
 *
 * BoundaryFinder
 *
 */

template<class Char, class String>
qs::BoundaryFinder<Char, String>::BoundaryFinder(const Char* pszMessage,
												 size_t nLen,
												 const Char* pszBoundary,
												 const Char* pszNewLine,
												 bool bAllowIncomplete) :
	p_(pszMessage),
	nLen_(nLen),
	nBoundaryLen_(0),
	pszNewLine_(pszNewLine),
	bAllowIncomplete_(bAllowIncomplete)
{
	assert(CharTraits<Char>::compare(pszMessage, pszNewLine_,
		CharTraits<Char>::getLength(pszNewLine_)) == 0);

	size_t nNewLineLen = CharTraits<Char>::getLength(pszNewLine_);
	size_t nBoundaryLen = CharTraits<Char>::getLength(pszBoundary);
	nBoundaryLen_ = nBoundaryLen + nNewLineLen + 2;
	basic_string_ptr<String> strBoundary(
		StringTraits<String>::allocString(nBoundaryLen_ + 1));
	Char* p = strBoundary.get();
	memcpy(p, pszNewLine_, nNewLineLen*sizeof(Char));
	p += nNewLineLen;
	*p++ = '-';
	*p++ = '-';
	memcpy(p, pszBoundary, nBoundaryLen*sizeof(Char));
	p += nBoundaryLen;
	*p = 0;

	pFindString_.reset(new BMFindString<String>(strBoundary.get(), nBoundaryLen_));

	const Char* pBegin = 0;
	const Char* pEnd = 0;
	getNextBoundary(pszMessage, nLen, &pBegin, &pEnd);
	p_ = pEnd;
	nLen_ = p_ ? nLen - (p_ - pszMessage) : 0;
}

template<class Char, class String>
qs::BoundaryFinder<Char, String>::~BoundaryFinder()
{
}

template<class Char, class String>
bool qs::BoundaryFinder<Char, String>::getNext(const Char** ppBegin,
											   const Char** ppEnd,
											   bool* pbEnd)
{
	assert(ppBegin);
	assert(ppEnd);
	assert(pbEnd);

	*ppBegin = 0;
	*ppEnd = 0;
	*pbEnd = false;

	if (p_) {
		const Char* pBegin = 0;
		const Char* pEnd = 0;
		getNextBoundary(p_, nLen_, &pBegin, &pEnd);
		if (pBegin) {
			*ppBegin = p_;
			*ppEnd = pBegin;
			*pbEnd = pEnd == 0;

			if (pEnd) {
				assert(pEnd <= p_ + nLen_);
				nLen_ -= pEnd - p_;
				p_ = pEnd;
			}
			else {
				nLen_ = 0;
				p_ = 0;
			}
		}
		else {
			if (bAllowIncomplete_) {
				*ppBegin = p_;
				*ppEnd = p_ + nLen_;
				*pbEnd = true;

				nLen_ = 0;
				p_ = 0;
			}
			else {
				return false;
			}
		}
	}
	else {
		*pbEnd = true;
	}

	return true;
}

template<class Char, class String>
void qs::BoundaryFinder<Char, String>::getNextBoundary(const Char* p,
													   size_t nLen,
													   const Char** ppBegin,
													   const Char** ppEnd)
{
	assert(p);
	assert(ppBegin);
	assert(ppEnd);

	*ppBegin = 0;
	*ppEnd = 0;

	size_t nNewLineLen = CharTraits<Char>::getLength(pszNewLine_);

	while (!*ppBegin) {
		const Char* pBegin = pFindString_->find(p, nLen);
		if (!pBegin)
			break;

		const Char* pEnd = pBegin + nBoundaryLen_;
		bool bEnd = pEnd + 1 < p + nLen && *pEnd == '-' && *(pEnd + 1) == '-';
		if (bEnd)
			pEnd += 2;
		while (pEnd < p + nLen && (*pEnd == ' ' || *pEnd == '\t'))
			++pEnd;

		if (bEnd) {
			*ppBegin = pBegin;
		}
		else if (pEnd + nNewLineLen <= p + nLen &&
			CharTraits<Char>::compare(pEnd, pszNewLine_, nNewLineLen) == 0) {
			*ppBegin = pBegin;
			*ppEnd = pEnd + nNewLineLen;
		}

		p = pBegin + 1;
	}
}

#endif // __QSMIME_INL__
<commit_msg>WCHAR version of FieldParserUtil::isNeedQuote works incorrectly. <BTS:528><commit_after>/*
 * $Id$
 *
 * Copyright(C) 1998-2004 Satoshi Nakamura
 * All rights reserved.
 *
 */

#ifndef __QSMIME_INL__
#define __QSMIME_INL__

/****************************************************************************
 *
 * FieldParserUtil
 *
 */

template<class String>
qs::basic_string_ptr<String> qs::FieldParserUtil<String>::getQString(const Char* psz,
																	 size_t nLen)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);

	StringBuffer<String> buf(nLen + 2);
	buf.append(Char('\"'));
	for (const Char* p = psz; p < psz + nLen; ++p) {
		if (*p == Char('\\') || *p == Char('\"'))
			buf.append(Char('\\'));
		buf.append(*p);
	}
	buf.append(Char('\"'));

	return buf.getString();
}

template<class String>
qs::basic_string_ptr<String> qs::FieldParserUtil<String>::getAtomOrQString(const Char* psz,
																		   size_t nLen)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);

	if (isNeedQuote(psz, nLen, true))
		return getQString(psz, nLen);
	else
		return StringTraits<String>::allocString(psz, nLen);
}

template<class String>
qs::basic_string_ptr<String> qs::FieldParserUtil<String>::getAtomsOrQString(const Char* psz,
																			size_t nLen)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);

	if (isNeedQuote(psz, nLen, false))
		return getQString(psz, nLen);
	else
		return StringTraits<String>::allocString(psz, nLen);
}

template<class String>
bool qs::FieldParserUtil<String>::isNeedQuote(const Char* psz,
											  size_t nLen,
											  bool bQuoteWhitespace)
{
	assert(psz);

	if (nLen == -1)
		nLen = CharTraits<Char>::getLength(psz);
	if (nLen == 0)
		return true;

	const Char* p = psz;
	while (p < psz + nLen) {
		if (unsigned int(*p) < 0x80) {
			if (FieldParser::isSpecial(char(*p)) ||
				(bQuoteWhitespace && (*p == Char(' ') || *p == Char('\t'))))
				break;
		}
		++p;
	}
	return p != psz + nLen;
}

/****************************************************************************
 *
 * BoundaryFinder
 *
 */

template<class Char, class String>
qs::BoundaryFinder<Char, String>::BoundaryFinder(const Char* pszMessage,
												 size_t nLen,
												 const Char* pszBoundary,
												 const Char* pszNewLine,
												 bool bAllowIncomplete) :
	p_(pszMessage),
	nLen_(nLen),
	nBoundaryLen_(0),
	pszNewLine_(pszNewLine),
	bAllowIncomplete_(bAllowIncomplete)
{
	assert(CharTraits<Char>::compare(pszMessage, pszNewLine_,
		CharTraits<Char>::getLength(pszNewLine_)) == 0);

	size_t nNewLineLen = CharTraits<Char>::getLength(pszNewLine_);
	size_t nBoundaryLen = CharTraits<Char>::getLength(pszBoundary);
	nBoundaryLen_ = nBoundaryLen + nNewLineLen + 2;
	basic_string_ptr<String> strBoundary(
		StringTraits<String>::allocString(nBoundaryLen_ + 1));
	Char* p = strBoundary.get();
	memcpy(p, pszNewLine_, nNewLineLen*sizeof(Char));
	p += nNewLineLen;
	*p++ = '-';
	*p++ = '-';
	memcpy(p, pszBoundary, nBoundaryLen*sizeof(Char));
	p += nBoundaryLen;
	*p = 0;

	pFindString_.reset(new BMFindString<String>(strBoundary.get(), nBoundaryLen_));

	const Char* pBegin = 0;
	const Char* pEnd = 0;
	getNextBoundary(pszMessage, nLen, &pBegin, &pEnd);
	p_ = pEnd;
	nLen_ = p_ ? nLen - (p_ - pszMessage) : 0;
}

template<class Char, class String>
qs::BoundaryFinder<Char, String>::~BoundaryFinder()
{
}

template<class Char, class String>
bool qs::BoundaryFinder<Char, String>::getNext(const Char** ppBegin,
											   const Char** ppEnd,
											   bool* pbEnd)
{
	assert(ppBegin);
	assert(ppEnd);
	assert(pbEnd);

	*ppBegin = 0;
	*ppEnd = 0;
	*pbEnd = false;

	if (p_) {
		const Char* pBegin = 0;
		const Char* pEnd = 0;
		getNextBoundary(p_, nLen_, &pBegin, &pEnd);
		if (pBegin) {
			*ppBegin = p_;
			*ppEnd = pBegin;
			*pbEnd = pEnd == 0;

			if (pEnd) {
				assert(pEnd <= p_ + nLen_);
				nLen_ -= pEnd - p_;
				p_ = pEnd;
			}
			else {
				nLen_ = 0;
				p_ = 0;
			}
		}
		else {
			if (bAllowIncomplete_) {
				*ppBegin = p_;
				*ppEnd = p_ + nLen_;
				*pbEnd = true;

				nLen_ = 0;
				p_ = 0;
			}
			else {
				return false;
			}
		}
	}
	else {
		*pbEnd = true;
	}

	return true;
}

template<class Char, class String>
void qs::BoundaryFinder<Char, String>::getNextBoundary(const Char* p,
													   size_t nLen,
													   const Char** ppBegin,
													   const Char** ppEnd)
{
	assert(p);
	assert(ppBegin);
	assert(ppEnd);

	*ppBegin = 0;
	*ppEnd = 0;

	size_t nNewLineLen = CharTraits<Char>::getLength(pszNewLine_);

	while (!*ppBegin) {
		const Char* pBegin = pFindString_->find(p, nLen);
		if (!pBegin)
			break;

		const Char* pEnd = pBegin + nBoundaryLen_;
		bool bEnd = pEnd + 1 < p + nLen && *pEnd == '-' && *(pEnd + 1) == '-';
		if (bEnd)
			pEnd += 2;
		while (pEnd < p + nLen && (*pEnd == ' ' || *pEnd == '\t'))
			++pEnd;

		if (bEnd) {
			*ppBegin = pBegin;
		}
		else if (pEnd + nNewLineLen <= p + nLen &&
			CharTraits<Char>::compare(pEnd, pszNewLine_, nNewLineLen) == 0) {
			*ppBegin = pBegin;
			*ppEnd = pEnd + nNewLineLen;
		}

		p = pBegin + 1;
	}
}

#endif // __QSMIME_INL__
<|endoftext|>