<commit_before>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** main.cpp
**
** V4L2 RTSP streamer
**
** H264 capture using V4L2
** RTSP using live555
**
** -------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>

#include <sstream>

// libv4l2
#include <linux/videodev2.h>
#include <libv4l2.h>

// live555
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>

// project
#include "logger.h"

#include "V4l2Device.h"
#include "V4l2Capture.h"
#include "V4l2Output.h"

#include "H264_V4l2DeviceSource.h"
#include "ServerMediaSubsession.h"

// -----------------------------------------
//    signal handler
// -----------------------------------------
char quit = 0;
void sighandler(int n)
{
	printf("SIGINT\n");
	quit =1;
}

// -----------------------------------------
//    add an RTSP session
// -----------------------------------------
void addSession(RTSPServer* rtspServer, const std::string & sessionName, ServerMediaSubsession *subSession)
{
	UsageEnvironment& env(rtspServer->envir());
	ServerMediaSession* sms = ServerMediaSession::createNew(env, sessionName.c_str());
	if (sms != NULL)
	{
		sms->addSubsession(subSession);
		rtspServer->addServerMediaSession(sms);

		char* url = rtspServer->rtspURL(sms);
		if (url != NULL)
		{
			LOG(NOTICE) << "Play this stream using the URL \"" << url << "\"";
			delete[] url;
		}
	}
}

// -----------------------------------------
//    entry point
// -----------------------------------------
int main(int argc, char** argv)
{
	// default parameters
	const char *dev_name = "/dev/video0";
	int format = V4L2_PIX_FMT_H264;
	int width = 640;
	int height = 480;
	int queueSize = 10;
	int fps = 25;
	unsigned short rtspPort = 8554;
	unsigned short rtspOverHTTPPort = 0;
	bool multicast = false;
	int verbose = 0;
	std::string outputFile;
	bool useMmap = true;
	std::string url = "unicast";
	std::string murl = "multicast";
	bool useThread = true;
	std::string maddr;
	bool repeatConfig = true;
	int timeout = 65;

	// decode parameters
	int c = 0;
	while ((c = getopt (argc, argv, "v::Q:O:" "I:P:T:m:u:M:ct:" "rsfF:W:H:" "h")) != -1)
	{
		switch (c)
		{
			case 'v':	verbose = 1; if (optarg && *optarg=='v') verbose++;  break;
			case 'Q':	queueSize = atoi(optarg); break;
			case 'O':	outputFile = optarg; break;
			// RTSP/RTP
			case 'I':       ReceivingInterfaceAddr = inet_addr(optarg); break;
			case 'P':	rtspPort = atoi(optarg); break;
			case 'T':	rtspOverHTTPPort = atoi(optarg); break;
			case 'u':	url = optarg; break;
			case 'm':	multicast = true; murl = optarg; break;
			case 'M':	multicast = true; maddr = optarg; break;
			case 'c':	repeatConfig = false; break;
			case 't':	timeout = atoi(optarg); break;
			// V4L2
			case 'r':	useMmap =  false; break;
			case 's':	useThread =  false; break;
			case 'f':	format = 0; break;
			case 'F':	fps = atoi(optarg); break;
			case 'W':	width = atoi(optarg); break;
			case 'H':	height = atoi(optarg); break;

			case 'h':
			default:
			{
				std::cout << argv[0] << " [-v[v]] [-Q queueSize] [-O file]"                                        << std::endl;
				std::cout << "\t          [-I interface] [-P RTSP port] [-T RTSP/HTTP port] [-m multicast url] [-u unicast url] [-M multicast addr] [-c] [-t timeout]" << std::endl;
				std::cout << "\t          [-r] [-s] [-W width] [-H height] [-F fps] [device] [device]"           << std::endl;
				std::cout << "\t -v       : verbose"                                                               << std::endl;
				std::cout << "\t -vv      : very verbose"                                                          << std::endl;
				std::cout << "\t -Q length: Number of frame queue  (default "<< queueSize << ")"                   << std::endl;
				std::cout << "\t -O output: Copy captured frame to a file or a V4L2 device"                        << std::endl;
				std::cout << "\t RTSP options :"                                                                   << std::endl;
				std::cout << "\t -I addr  : RTSP interface (default autodetect)"                                   << std::endl;
				std::cout << "\t -P port  : RTSP port (default "<< rtspPort << ")"                                 << std::endl;
				std::cout << "\t -T port  : RTSP over HTTP port (default "<< rtspOverHTTPPort << ")"               << std::endl;
				std::cout << "\t -u url   : unicast url (default " << url << ")"                                   << std::endl;
				std::cout << "\t -m url   : multicast url (default " << murl << ")"                                << std::endl;
				std::cout << "\t -M addr  : multicast group:port (default is random_address:20000)"                << std::endl;
				std::cout << "\t -c       : don't repeat config (default repeat config before IDR frame)"          << std::endl;
				std::cout << "\t -t secs  : RTCP expiration timeout (default " << timeout << ")"                   << std::endl;
				std::cout << "\t V4L2 options :"                                                                   << std::endl;
				std::cout << "\t -r       : V4L2 capture using read interface (default use memory mapped buffers)" << std::endl;
				std::cout << "\t -s       : V4L2 capture using live555 mainloop (default use a reader thread)"     << std::endl;
				std::cout << "\t -f       : V4L2 capture using current format (-W,-H,-F are ignore)"               << std::endl;
				std::cout << "\t -W width : V4L2 capture width (default "<< width << ")"                           << std::endl;
				std::cout << "\t -H height: V4L2 capture height (default "<< height << ")"                         << std::endl;
				std::cout << "\t -F fps   : V4L2 capture framerate (default "<< fps << ")"                         << std::endl;
				std::cout << "\t device   : V4L2 capture device (default "<< dev_name << ")"                       << std::endl;
				exit(0);
			}
		}
	}
	std::list<std::string> devList;
	while (optind<argc)
	{
		devList.push_back(argv[optind]);
		optind++;
	}
	if (devList.empty())
	{
		devList.push_back(dev_name);
	}

	// init logger
	initLogger(verbose);

	// create live555 environment
	TaskScheduler* scheduler = BasicTaskScheduler::createNew();
	UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);

	// split multicast info
	std::istringstream is(maddr);
	std::string ip;
	getline(is, ip, ':');
	struct in_addr destinationAddress;
	destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
	if (!ip.empty())
	{
		destinationAddress.s_addr = inet_addr(ip.c_str());
	}

	std::string port;
	getline(is, port, ':');
	unsigned short rtpPortNum = 20000;
	if (!port.empty())
	{
		rtpPortNum = atoi(port.c_str());
	}
	unsigned short rtcpPortNum = rtpPortNum+1;
	unsigned char ttl = 5;

	// create RTSP server
	UserAuthenticationDatabase* authDB = NULL;
	RTSPServer* rtspServer = RTSPServer::createNew(*env, rtspPort, authDB, timeout);
	if (rtspServer == NULL)
	{
		LOG(ERROR) << "Failed to create RTSP server: " << env->getResultMsg();
	}
	else
	{
		// set http tunneling
		if (rtspOverHTTPPort)
		{
			rtspServer->setUpTunnelingOverHTTP(rtspOverHTTPPort);
		}

		std::list<std::string>::iterator devIt;
		for ( devIt=devList.begin() ; devIt!=devList.end() ; ++devIt)
		{
			std::string deviceName(*devIt);

			// Init capture
			LOG(NOTICE) << "Create V4L2 Source..." << deviceName;
			V4L2DeviceParameters param(deviceName.c_str(),format,width,height,fps, verbose);
			V4l2Capture* videoCapture = V4l2DeviceFactory::CreateVideoCapure(param, useMmap);
			if (videoCapture)
			{
				V4L2DeviceParameters outparam(outputFile.c_str(), videoCapture->getFormat(), videoCapture->getWidth(), videoCapture->getHeight(), 0,verbose);
				V4l2Output out(outparam);

				LOG(NOTICE) << "Start V4L2 Capture..." << deviceName;
				if (!videoCapture->captureStart())
				{
					LOG(NOTICE) << "Cannot start V4L2 Capture for:" << deviceName;
				}
				V4L2DeviceSource* videoES = NULL;
				if (videoCapture->getFormat() == V4L2_PIX_FMT_H264)
				{
					videoES = H264_V4L2DeviceSource::createNew(*env, param, videoCapture, out.getFd(), queueSize, useThread, repeatConfig);
				}
				else
				{
					videoES = V4L2DeviceSource::createNew(*env, param, videoCapture, out.getFd(), queueSize, useThread);
				}
				if (videoES == NULL)
				{
					LOG(FATAL) << "Unable to create source for device " << deviceName;
					delete videoCapture;
				}
				else
				{
					// extend buffer size if needed
					if (videoCapture->getBufferSize() > OutPacketBuffer::maxSize)
					{
						OutPacketBuffer::maxSize = videoCapture->getBufferSize();
					}

					StreamReplicator* replicator = StreamReplicator::createNew(*env, videoES, false);

					std::string baseUrl;
					if (devList.size() > 1)
					{
						baseUrl = basename(deviceName.c_str());
						baseUrl.append("/");
					}

					// Create Multicast Session
					if (multicast)
					{
						LOG(NOTICE) << "RTP  address " << inet_ntoa(destinationAddress) << ":" << rtpPortNum;
						LOG(NOTICE) << "RTCP address " << inet_ntoa(destinationAddress) << ":" << rtcpPortNum;
						addSession(rtspServer, baseUrl+murl, MulticastServerMediaSubsession::createNew(*env,destinationAddress, Port(rtpPortNum), Port(rtcpPortNum), ttl, replicator,format));

						// increment ports for next sessions
						rtpPortNum+=2;
						rtcpPortNum+=2;

					}
					// Create Unicast Session
					addSession(rtspServer, baseUrl+url, UnicastServerMediaSubsession::createNew(*env,replicator,format));
				}
			}
		}

		// main loop
		signal(SIGINT,sighandler);
		env->taskScheduler().doEventLoop(&quit);
		LOG(NOTICE) << "Exiting....";

		Medium::close(rtspServer);
	}

	env->reclaim();
	delete scheduler;

	return 0;
}

<commit_msg>allow to stream VP8<commit_after>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** main.cpp
**
** V4L2 RTSP streamer
**
** H264 capture using V4L2
** RTSP using live555
**
** -------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>

#include <sstream>

// libv4l2
#include <linux/videodev2.h>
#include <libv4l2.h>

// live555
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>

// project
#include "logger.h"

#include "V4l2Device.h"
#include "V4l2Capture.h"
#include "V4l2Output.h"

#include "H264_V4l2DeviceSource.h"
#include "ServerMediaSubsession.h"

// -----------------------------------------
//    signal handler
// -----------------------------------------
char quit = 0;
void sighandler(int n)
{
	printf("SIGINT\n");
	quit =1;
}

// -----------------------------------------
//    add an RTSP session
// -----------------------------------------
void addSession(RTSPServer* rtspServer, const std::string & sessionName, ServerMediaSubsession *subSession)
{
	UsageEnvironment& env(rtspServer->envir());
	ServerMediaSession* sms = ServerMediaSession::createNew(env, sessionName.c_str());
	if (sms != NULL)
	{
		sms->addSubsession(subSession);
		rtspServer->addServerMediaSession(sms);

		char* url = rtspServer->rtspURL(sms);
		if (url != NULL)
		{
			LOG(NOTICE) << "Play this stream using the URL \"" << url << "\"";
			delete[] url;
		}
	}
}

// -----------------------------------------
//    entry point
// -----------------------------------------
int main(int argc, char** argv)
{
	// default parameters
	const char *dev_name = "/dev/video0";
	int format = V4L2_PIX_FMT_H264;
	int width = 640;
	int height = 480;
	int queueSize = 10;
	int fps = 25;
	unsigned short rtspPort = 8554;
	unsigned short rtspOverHTTPPort = 0;
	bool multicast = false;
	int verbose = 0;
	std::string outputFile;
	bool useMmap = true;
	std::string url = "unicast";
	std::string murl = "multicast";
	bool useThread = true;
	std::string maddr;
	bool repeatConfig = true;
	int timeout = 65;

	// decode parameters
	int c = 0;
	while ((c = getopt (argc, argv, "v::Q:O:" "I:P:T:m:u:M:ct:" "rsfF:W:H:" "h")) != -1)
	{
		switch (c)
		{
			case 'v':	verbose = 1; if (optarg && *optarg=='v') verbose++;  break;
			case 'Q':	queueSize = atoi(optarg); break;
			case 'O':	outputFile = optarg; break;
			// RTSP/RTP
			case 'I':       ReceivingInterfaceAddr = inet_addr(optarg); break;
			case 'P':	rtspPort = atoi(optarg); break;
			case 'T':	rtspOverHTTPPort = atoi(optarg); break;
			case 'u':	url = optarg; break;
			case 'm':	multicast = true; murl = optarg; break;
			case 'M':	multicast = true; maddr = optarg; break;
			case 'c':	repeatConfig = false; break;
			case 't':	timeout = atoi(optarg); break;
			// V4L2
			case 'r':	useMmap =  false; break;
			case 's':	useThread =  false; break;
			case 'f':	format = 0; break;
			case 'F':	fps = atoi(optarg); break;
			case 'W':	width = atoi(optarg); break;
			case 'H':	height = atoi(optarg); break;

			case 'h':
			default:
			{
				std::cout << argv[0] << " [-v[v]] [-Q queueSize] [-O file]"                                        << std::endl;
				std::cout << "\t          [-I interface] [-P RTSP port] [-T RTSP/HTTP port] [-m multicast url] [-u unicast url] [-M multicast addr] [-c] [-t timeout]" << std::endl;
				std::cout << "\t          [-r] [-s] [-W width] [-H height] [-F fps] [device] [device]"           << std::endl;
				std::cout << "\t -v       : verbose"                                                               << std::endl;
				std::cout << "\t -vv      : very verbose"                                                          << std::endl;
				std::cout << "\t -Q length: Number of frame queue  (default "<< queueSize << ")"                   << std::endl;
				std::cout << "\t -O output: Copy captured frame to a file or a V4L2 device"                        << std::endl;
				std::cout << "\t RTSP options :"                                                                   << std::endl;
				std::cout << "\t -I addr  : RTSP interface (default autodetect)"                                   << std::endl;
				std::cout << "\t -P port  : RTSP port (default "<< rtspPort << ")"                                 << std::endl;
				std::cout << "\t -T port  : RTSP over HTTP port (default "<< rtspOverHTTPPort << ")"               << std::endl;
				std::cout << "\t -u url   : unicast url (default " << url << ")"                                   << std::endl;
				std::cout << "\t -m url   : multicast url (default " << murl << ")"                                << std::endl;
				std::cout << "\t -M addr  : multicast group:port (default is random_address:20000)"                << std::endl;
				std::cout << "\t -c       : don't repeat config (default repeat config before IDR frame)"          << std::endl;
				std::cout << "\t -t secs  : RTCP expiration timeout (default " << timeout << ")"                   << std::endl;
				std::cout << "\t V4L2 options :"                                                                   << std::endl;
				std::cout << "\t -r       : V4L2 capture using read interface (default use memory mapped buffers)" << std::endl;
				std::cout << "\t -s       : V4L2 capture using live555 mainloop (default use a reader thread)"     << std::endl;
				std::cout << "\t -f       : V4L2 capture using current format (-W,-H,-F are ignore)"               << std::endl;
				std::cout << "\t -W width : V4L2 capture width (default "<< width << ")"                           << std::endl;
				std::cout << "\t -H height: V4L2 capture height (default "<< height << ")"                         << std::endl;
				std::cout << "\t -F fps   : V4L2 capture framerate (default "<< fps << ")"                         << std::endl;
				std::cout << "\t device   : V4L2 capture device (default "<< dev_name << ")"                       << std::endl;
				exit(0);
			}
		}
	}
	std::list<std::string> devList;
	while (optind<argc)
	{
		devList.push_back(argv[optind]);
		optind++;
	}
	if (devList.empty())
	{
		devList.push_back(dev_name);
	}

	// init logger
	initLogger(verbose);

	// create live555 environment
	TaskScheduler* scheduler = BasicTaskScheduler::createNew();
	UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);

	// split multicast info
	std::istringstream is(maddr);
	std::string ip;
	getline(is, ip, ':');
	struct in_addr destinationAddress;
	destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
	if (!ip.empty())
	{
		destinationAddress.s_addr = inet_addr(ip.c_str());
	}

	std::string port;
	getline(is, port, ':');
	unsigned short rtpPortNum = 20000;
	if (!port.empty())
	{
		rtpPortNum = atoi(port.c_str());
	}
	unsigned short rtcpPortNum = rtpPortNum+1;
	unsigned char ttl = 5;

	// create RTSP server
	UserAuthenticationDatabase* authDB = NULL;
	RTSPServer* rtspServer = RTSPServer::createNew(*env, rtspPort, authDB, timeout);
	if (rtspServer == NULL)
	{
		LOG(ERROR) << "Failed to create RTSP server: " << env->getResultMsg();
	}
	else
	{
		// set http tunneling
		if (rtspOverHTTPPort)
		{
			rtspServer->setUpTunnelingOverHTTP(rtspOverHTTPPort);
		}

		std::list<std::string>::iterator devIt;
		for ( devIt=devList.begin() ; devIt!=devList.end() ; ++devIt)
		{
			std::string deviceName(*devIt);

			// Init capture
			LOG(NOTICE) << "Create V4L2 Source..." << deviceName;
			V4L2DeviceParameters param(deviceName.c_str(),format,width,height,fps, verbose);
			V4l2Capture* videoCapture = V4l2DeviceFactory::CreateVideoCapure(param, useMmap);
			if (videoCapture)
			{
				format = videoCapture->getFormat();
				V4L2DeviceParameters outparam(outputFile.c_str(), videoCapture->getFormat(), videoCapture->getWidth(), videoCapture->getHeight(), 0,verbose);
				V4l2Output out(outparam);

				LOG(NOTICE) << "Start V4L2 Capture..." << deviceName;
				if (!videoCapture->captureStart())
				{
					LOG(NOTICE) << "Cannot start V4L2 Capture for:" << deviceName;
				}
				V4L2DeviceSource* videoES = NULL;
				if (format == V4L2_PIX_FMT_H264)
				{
					videoES = H264_V4L2DeviceSource::createNew(*env, param, videoCapture, out.getFd(), queueSize, useThread, repeatConfig);
				}
				else
				{
					videoES = V4L2DeviceSource::createNew(*env, param, videoCapture, out.getFd(), queueSize, useThread);
				}
				if (videoES == NULL)
				{
					LOG(FATAL) << "Unable to create source for device " << deviceName;
					delete videoCapture;
				}
				else
				{
					// extend buffer size if needed
					if (videoCapture->getBufferSize() > OutPacketBuffer::maxSize)
					{
						OutPacketBuffer::maxSize = videoCapture->getBufferSize();
					}

					StreamReplicator* replicator = StreamReplicator::createNew(*env, videoES, false);

					std::string baseUrl;
					if (devList.size() > 1)
					{
						baseUrl = basename(deviceName.c_str());
						baseUrl.append("/");
					}

					// Create Multicast Session
					if (multicast)
					{
						LOG(NOTICE) << "RTP  address " << inet_ntoa(destinationAddress) << ":" << rtpPortNum;
						LOG(NOTICE) << "RTCP address " << inet_ntoa(destinationAddress) << ":" << rtcpPortNum;
						addSession(rtspServer, baseUrl+murl, MulticastServerMediaSubsession::createNew(*env,destinationAddress, Port(rtpPortNum), Port(rtcpPortNum), ttl, replicator,format));

						// increment ports for next sessions
						rtpPortNum+=2;
						rtcpPortNum+=2;

					}
					// Create Unicast Session
					addSession(rtspServer, baseUrl+url, UnicastServerMediaSubsession::createNew(*env,replicator,format));
				}
			}
		}

		// main loop
		signal(SIGINT,sighandler);
		env->taskScheduler().doEventLoop(&quit);
		LOG(NOTICE) << "Exiting....";

		Medium::close(rtspServer);
	}

	env->reclaim();
	delete scheduler;

	return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include "database.hh"
#include "net/byteorder.hh"

bool
less_unsigned(const bytes& v1, const bytes& v2) {
    return std::lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end(),
            [](int8_t v1, int8_t v2) { return uint8_t(v1) < uint8_t(v2); });
}

template <typename T, typename Compare>
bool
abstract_type::default_less(const bytes& v1, const bytes& v2, Compare compare) {
    auto o1 = deserialize(v1);
    auto o2 = deserialize(v2);
    if (!o1) {
        return bool(o2);
    }
    if (!o2) {
        return false;
    }
    auto& x1 = boost::any_cast<const T&>(*o1);
    auto& x2 = boost::any_cast<const T&>(*o2);
    return compare(x1, x2);
}

template <typename T>
struct simple_type_impl : abstract_type {
    simple_type_impl(sstring name) : abstract_type(std::move(name)) {}
    virtual bool less(const bytes& v1, const bytes& v2) override {
        return default_less<T>(v1, v2);
    }
};

struct int32_type_impl : simple_type_impl<int32_t> {
    int32_type_impl() : simple_type_impl<int32_t>("int32") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<const int32_t&>(value);
        auto u = net::hton(uint32_t(v));
        out.write(reinterpret_cast<const char*>(&u), sizeof(u));
    }
    virtual object_opt deserialize(std::istream& in) {
        uint32_t u;
        auto n = in.rdbuf()->sgetn(reinterpret_cast<char*>(&u), sizeof(u));
        if (!n) {
            return {};
        }
        if (n != 4) {
            throw marshal_exception();
        }
        auto v = int32_t(net::ntoh(u));
        return boost::any(v);
    }
};

struct long_type_impl : simple_type_impl<int64_t> {
    long_type_impl() : simple_type_impl<int64_t>("long") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<const int64_t&>(value);
        auto u = net::hton(uint64_t(v));
        out.write(reinterpret_cast<const char*>(&u), sizeof(u));
    }
    virtual object_opt deserialize(std::istream& in) {
        uint64_t u;
        auto n = in.rdbuf()->sgetn(reinterpret_cast<char*>(&u), sizeof(u));
        if (!n) {
            return {};
        }
        if (n != 8) {
            throw marshal_exception();
        }
        auto v = int64_t(net::ntoh(u));
        return boost::any(v);
    }
};

struct string_type_impl : public abstract_type {
    string_type_impl(sstring name) : abstract_type(name) {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto& v = boost::any_cast<const sstring&>(value);
        out.write(v.c_str(), v.size());
    }
    virtual object_opt deserialize(std::istream& in) {
        std::vector<char> tmp(std::istreambuf_iterator<char>(in.rdbuf()),
                              std::istreambuf_iterator<char>());
        // FIXME: validation?
        return boost::any(sstring(tmp.data(), tmp.size()));
    }
    virtual bool less(const bytes& v1, const bytes& v2) override {
        return less_unsigned(v1, v2);
    }
};

struct bytes_type_impl : public abstract_type {
    bytes_type_impl() : abstract_type("bytes") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto& v = boost::any_cast<const bytes&>(value);
        out.write(v.c_str(), v.size());
    }
    virtual object_opt deserialize(std::istream& in) {
        std::vector<char> tmp(std::istreambuf_iterator<char>(in.rdbuf()),
                              std::istreambuf_iterator<char>());
        return boost::any(bytes(reinterpret_cast<const char*>(tmp.data()), tmp.size()));
    }
    virtual bool less(const bytes& v1, const bytes& v2) override {
        return less_unsigned(v1, v2);
    }
};

struct boolean_type_impl : public simple_type_impl<bool> {
    boolean_type_impl() : simple_type_impl<bool>("boolean") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<bool>(value);
        char c = v;
        out.put(c);
    }
    virtual object_opt deserialize(std::istream& in) override {
        char tmp;
        auto n = in.rdbuf()->sgetn(&tmp, 1);
        if (n == 0) {
            return {};
        }
        return boost::any(tmp != 0);
    }
};

thread_local shared_ptr<abstract_type> int_type(make_shared<int32_type_impl>());
thread_local shared_ptr<abstract_type> long_type(make_shared<long_type_impl>());
thread_local shared_ptr<abstract_type> ascii_type(make_shared<string_type_impl>("ascii"));
thread_local shared_ptr<abstract_type> bytes_type(make_shared<bytes_type_impl>());
thread_local shared_ptr<abstract_type> utf8_type(make_shared<string_type_impl>("utf8"));
thread_local shared_ptr<abstract_type> boolean_type(make_shared<boolean_type_impl>());

partition::partition(column_family& cf)
        : rows(key_compare(cf.clustering_key_type)) {
}

column_family::column_family(shared_ptr<abstract_type> partition_key_type,
                             shared_ptr<abstract_type> clustering_key_type)
        : partition_key_type(std::move(partition_key_type))
        , clustering_key_type(std::move(clustering_key_type))
        , partitions(key_compare(this->partition_key_type)) {
}

partition*
column_family::find_partition(const bytes& key) {
    auto i = partitions.find(key);
    return i == partitions.end() ? nullptr : &i->second;
}

row*
column_family::find_row(const bytes& partition_key, const bytes& clustering_key) {
    partition* p = find_partition(partition_key);
    if (!p) {
        return nullptr;
    }
    auto i = p->rows.find(clustering_key);
    return i == p->rows.end() ? nullptr : &i->second;
}

partition&
column_family::find_or_create_partition(const bytes& key) {
    // call lower_bound so we have a hint for the insert, just in case.
    auto i = partitions.lower_bound(key);
    if (i == partitions.end() || key != i->first) {
        i = partitions.emplace_hint(i, std::make_pair(std::move(key), partition(*this)));
    }
    return i->second;
}

row&
column_family::find_or_create_row(const bytes& partition_key, const bytes& clustering_key) {
    partition& p = find_or_create_partition(partition_key);
    // call lower_bound so we have a hint for the insert, just in case.
    auto i = p.rows.lower_bound(clustering_key);
    if (i == p.rows.end() || clustering_key != i->first) {
        i = p.rows.emplace_hint(i, std::make_pair(std::move(clustering_key), row()));
    }
    return i->second;
}
<commit_msg>db: add date_type<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include "database.hh"
#include "net/byteorder.hh"
#include "db_clock.hh"

bool
less_unsigned(const bytes& v1, const bytes& v2) {
    return std::lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end(),
            [](int8_t v1, int8_t v2) { return uint8_t(v1) < uint8_t(v2); });
}

template <typename T, typename Compare>
bool
abstract_type::default_less(const bytes& v1, const bytes& v2, Compare compare) {
    auto o1 = deserialize(v1);
    auto o2 = deserialize(v2);
    if (!o1) {
        return bool(o2);
    }
    if (!o2) {
        return false;
    }
    auto& x1 = boost::any_cast<const T&>(*o1);
    auto& x2 = boost::any_cast<const T&>(*o2);
    return compare(x1, x2);
}

template <typename T>
struct simple_type_impl : abstract_type {
    simple_type_impl(sstring name) : abstract_type(std::move(name)) {}
    virtual bool less(const bytes& v1, const bytes& v2) override {
        return default_less<T>(v1, v2);
    }
};

struct int32_type_impl : simple_type_impl<int32_t> {
    int32_type_impl() : simple_type_impl<int32_t>("int32") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<const int32_t&>(value);
        auto u = net::hton(uint32_t(v));
        out.write(reinterpret_cast<const char*>(&u), sizeof(u));
    }
    virtual object_opt deserialize(std::istream& in) {
        uint32_t u;
        auto n = in.rdbuf()->sgetn(reinterpret_cast<char*>(&u), sizeof(u));
        if (!n) {
            return {};
        }
        if (n != 4) {
            throw marshal_exception();
        }
        auto v = int32_t(net::ntoh(u));
        return boost::any(v);
    }
};

struct long_type_impl : simple_type_impl<int64_t> {
    long_type_impl() : simple_type_impl<int64_t>("long") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<const int64_t&>(value);
        auto u = net::hton(uint64_t(v));
        out.write(reinterpret_cast<const char*>(&u), sizeof(u));
    }
    virtual object_opt deserialize(std::istream& in) {
        uint64_t u;
        auto n = in.rdbuf()->sgetn(reinterpret_cast<char*>(&u), sizeof(u));
        if (!n) {
            return {};
        }
        if (n != 8) {
            throw marshal_exception();
        }
        auto v = int64_t(net::ntoh(u));
        return boost::any(v);
    }
};

struct string_type_impl : public abstract_type {
    string_type_impl(sstring name) : abstract_type(name) {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto& v = boost::any_cast<const sstring&>(value);
        out.write(v.c_str(), v.size());
    }
    virtual object_opt deserialize(std::istream& in) {
        std::vector<char> tmp(std::istreambuf_iterator<char>(in.rdbuf()),
                              std::istreambuf_iterator<char>());
        // FIXME: validation?
        return boost::any(sstring(tmp.data(), tmp.size()));
    }
    virtual bool less(const bytes& v1, const bytes& v2) override {
        return less_unsigned(v1, v2);
    }
};

struct bytes_type_impl : public abstract_type {
    bytes_type_impl() : abstract_type("bytes") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto& v = boost::any_cast<const bytes&>(value);
        out.write(v.c_str(), v.size());
    }
    virtual object_opt deserialize(std::istream& in) {
        std::vector<char> tmp(std::istreambuf_iterator<char>(in.rdbuf()),
                              std::istreambuf_iterator<char>());
        return boost::any(bytes(reinterpret_cast<const char*>(tmp.data()), tmp.size()));
    }
    virtual bool less(const bytes& v1, const bytes& v2) override {
        return less_unsigned(v1, v2);
    }
};

struct boolean_type_impl : public simple_type_impl<bool> {
    boolean_type_impl() : simple_type_impl<bool>("boolean") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<bool>(value);
        char c = v;
        out.put(c);
    }
    virtual object_opt deserialize(std::istream& in) override {
        char tmp;
        auto n = in.rdbuf()->sgetn(&tmp, 1);
        if (n == 0) {
            return {};
        }
        return boost::any(tmp != 0);
    }
};

struct date_type_impl : public abstract_type {
    date_type_impl() : abstract_type("date") {}
    virtual void serialize(const boost::any& value, std::ostream& out) override {
        auto v = boost::any_cast<db_clock::time_point>(value);
        int64_t i = v.time_since_epoch().count();
        i = net::hton(uint64_t(i));
        out.write(reinterpret_cast<char*>(&i), 8);
    }
    virtual object_opt deserialize(std::istream& in) override {
        int64_t tmp;
        auto n = in.rdbuf()->sgetn(reinterpret_cast<char*>(&tmp), 8);
        if (n == 0) {
            return {};
        }
        if (n != 8) {
            throw marshal_exception();
        }
        tmp = net::ntoh(uint64_t(tmp));
        return boost::any(db_clock::time_point(db_clock::duration(tmp)));
    }
    virtual bool less(const bytes& b1, const bytes& b2) override {
        // DateType has a bug where it compares the values as an unsigned type.
        // Preserve this bug.
        return default_less<db_clock::time_point>(b1, b2, [] (db_clock::time_point t1, db_clock::time_point t2) {
            return uint64_t(t1.time_since_epoch().count() < t2.time_since_epoch().count());
        });
    }
};

thread_local shared_ptr<abstract_type> int_type(make_shared<int32_type_impl>());
thread_local shared_ptr<abstract_type> long_type(make_shared<long_type_impl>());
thread_local shared_ptr<abstract_type> ascii_type(make_shared<string_type_impl>("ascii"));
thread_local shared_ptr<abstract_type> bytes_type(make_shared<bytes_type_impl>());
thread_local shared_ptr<abstract_type> utf8_type(make_shared<string_type_impl>("utf8"));
thread_local shared_ptr<abstract_type> boolean_type(make_shared<boolean_type_impl>());
thread_local shared_ptr<abstract_type> date_type(make_shared<date_type_impl>());

partition::partition(column_family& cf)
        : rows(key_compare(cf.clustering_key_type)) {
}

column_family::column_family(shared_ptr<abstract_type> partition_key_type,
                             shared_ptr<abstract_type> clustering_key_type)
        : partition_key_type(std::move(partition_key_type))
        , clustering_key_type(std::move(clustering_key_type))
        , partitions(key_compare(this->partition_key_type)) {
}

partition*
column_family::find_partition(const bytes& key) {
    auto i = partitions.find(key);
    return i == partitions.end() ? nullptr : &i->second;
}

row*
column_family::find_row(const bytes& partition_key, const bytes& clustering_key) {
    partition* p = find_partition(partition_key);
    if (!p) {
        return nullptr;
    }
    auto i = p->rows.find(clustering_key);
    return i == p->rows.end() ? nullptr : &i->second;
}

partition&
column_family::find_or_create_partition(const bytes& key) {
    // call lower_bound so we have a hint for the insert, just in case.
    auto i = partitions.lower_bound(key);
    if (i == partitions.end() || key != i->first) {
        i = partitions.emplace_hint(i, std::make_pair(std::move(key), partition(*this)));
    }
    return i->second;
}

row&
column_family::find_or_create_row(const bytes& partition_key, const bytes& clustering_key) {
    partition& p = find_or_create_partition(partition_key);
    // call lower_bound so we have a hint for the insert, just in case.
    auto i = p.rows.lower_bound(clustering_key);
    if (i == p.rows.end() || clustering_key != i->first) {
        i = p.rows.emplace_hint(i, std::make_pair(std::move(clustering_key), row()));
    }
    return i->second;
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////////
// This file is part of EasyRPG.
//
// EasyRPG is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// EasyRPG 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////

#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

#include "ldb_reader.h"
#include "lmt_reader.h"
#include "lmu_reader.h"
#include "lsd_reader.h"

enum FileTypes
{
	FileType_LCF_MapUnit,
	FileType_LCF_SaveData,
	FileType_LCF_Database,
	FileType_LCF_MapTree,
	FileType_XML_MapUnit,
	FileType_XML_SaveData,
	FileType_XML_Database,
	FileType_XML_MapTree,
	FileType_Invalid
};

std::string GetFilename(const std::string& str);
FileTypes GetFiletype(const std::string& in_file, std::string& out_extension);
void PrintReaderError(const std::string data);
int ReaderWriteToFile(const std::string& in, const std::string& out, FileTypes in_type);

int main(int argc, char** argv)
{
	if (argc <= 1)
	{
		std::cerr << "Lcf2Xml - Converts RPG Maker 2k/2k3 Files to XML and vice versa" << std::endl;
		std::cerr << "Usage: lcf2xml [FILE] [OUTFILE]" << std::endl;
		//std::cerr << "If OUTFILE is missing the resulting file is named FILE with the extension replaced" << std::endl;
		return 1;
	}

	std::string infile;
	std::string outfile;

	infile = argv[1];

	FileTypes type;
	std::string extension;

	if (argc >= 3)
	{
		// OUTFILE
		outfile = argv[2];
		type = GetFiletype(infile, extension);
	}
	else
	{
		// No OUTFILE, add extension based on detected filetype
		outfile = GetFilename(infile);
		type = GetFiletype(infile, extension);
		outfile += extension;
	}

	return ReaderWriteToFile(infile, outfile, type);
}

/// Returns the filename (without extension)
std::string GetFilename(const std::string& str)
{
	std::string s = str;
#ifdef _WIN32
	std::replace(s.begin(), s.end(), '\\', '/');
#endif
	// Extension
	size_t found = s.find_last_of(".");
	if (found != std::string::npos)
	{
		s = s.substr(0, found);
	}

	// Filename
	found = s.find_last_of("/");
	if (found == std::string::npos)
	{
		return s;
	}

	s = s.substr(found + 1);
	return s;
}

/// Uses heuristics to detect the file type
FileTypes GetFiletype(const std::string& in_file, std::string& out_extension)
{
	std::ifstream in(in_file.c_str());

	char buf[128];
	memset(buf, '\0', 128);

	in.seekg(1, std::ios::beg);
	in.read(buf, 10);
	std::string input(buf);

	out_extension = ".xml";
	if (input == "LcfDataBas") {
		return FileType_LCF_Database;
	} else if (input == "LcfMapTree") {
		return FileType_LCF_MapTree;
	} else if (input == "LcfSaveDat") {
		return FileType_LCF_SaveData;
	} else if (input == "LcfMapUnit") {
		return FileType_LCF_MapUnit;
	} else if (input == "?xml versi") {
		in.read(buf, 128);
		std::string in(buf);

		size_t pos = in.find('<');
		if (pos != std::string::npos)
		{
			in = in.substr(pos + 1, 3);
			if (in == "LDB") {
				out_extension = ".ldb";
				return FileType_XML_Database;
			} else if (in == "LMT") {
				out_extension = ".lmt";
				return FileType_XML_MapTree;
			} else if (in == "LSD") {
				out_extension = ".lsd";
				return FileType_XML_SaveData;
			} else if (in == "LMU") {
				out_extension = ".lmu";
				return FileType_XML_MapUnit;
			}
		}
	}

	out_extension = "";
	return FileType_Invalid;
}

/// Utility func for errors
void PrintReaderError(const std::string data)
{
	std::cerr << data << " error: " << LcfReader::GetError() << std::endl;
}

#define LCFXML_ERROR(cond, text) \
	if (cond) {\
		PrintReaderError(text);\
		return 2;\
	}

/// Takes data from in and writes converted data into out using libreaders
int ReaderWriteToFile(const std::string& in, const std::string& out, FileTypes in_type)
{
	switch (in_type)
	{
		case FileType_LCF_MapUnit:
		{
			std::auto_ptr<RPG::Map> file = LMU_Reader::Load(in);
			LCFXML_ERROR(file.get() == NULL, "LMU load");
			LCFXML_ERROR(!LMU_Reader::SaveXml(out, *file), "LMU XML save");
			break;
		}
		case FileType_LCF_SaveData:
		{
			std::auto_ptr<RPG::Save> file = LSD_Reader::Load(in);
			LCFXML_ERROR(file.get() == NULL, "LSD load");
			LCFXML_ERROR(!LSD_Reader::SaveXml(out, *file), "LSD XML save");
			break;
		}
		case FileType_LCF_Database:
		{
			LCFXML_ERROR(!LDB_Reader::Load(in), "LDB load");
			LCFXML_ERROR(!LDB_Reader::SaveXml(out), "LDB XML save");
			break;
		}
		case FileType_LCF_MapTree:
		{
			LCFXML_ERROR(!LMT_Reader::Load(in), "LMT load");
			LCFXML_ERROR(!LMT_Reader::SaveXml(out), "LMT XML save");
			break;
		}
		case FileType_XML_MapUnit:
		{
			std::auto_ptr<RPG::Map> file = LMU_Reader::LoadXml(in);
			LCFXML_ERROR(file.get() == NULL, "LMU XML load");
			LCFXML_ERROR(!LMU_Reader::Save(out, *file), "LMU save");
			break;
		}
		case FileType_XML_SaveData:
		{
			std::auto_ptr<RPG::Save> file = LSD_Reader::LoadXml(in);
			LCFXML_ERROR(file.get() == NULL, "LSD XML load");
			LCFXML_ERROR(!LSD_Reader::Save(out, *file), "LSD save");
			break;
		}
		case FileType_XML_Database:
		{
			LCFXML_ERROR(!LDB_Reader::LoadXml(in), "LDB XML load");
			LCFXML_ERROR(!LDB_Reader::Save(out), "LDB save");
			break;
		}
		case FileType_XML_MapTree:
		{
			LCFXML_ERROR(!LMT_Reader::LoadXml(in), "LMT XML load");
			LCFXML_ERROR(!LMT_Reader::Save(out), "LMT save");
			break;
		}
		case FileType_Invalid:
		{
			std::cerr << in << " unsupported" << std::endl;
			return 2;
		}
	}

	return 0;
}
<commit_msg>Proper javadoc-style syntax.<commit_after>/*
 * This file is part of EasyRPG.
 *
 * EasyRPG is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * EasyRPG 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
 */

#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

#include "ldb_reader.h"
#include "lmt_reader.h"
#include "lmu_reader.h"
#include "lsd_reader.h"

enum FileTypes
{
	FileType_LCF_MapUnit,
	FileType_LCF_SaveData,
	FileType_LCF_Database,
	FileType_LCF_MapTree,
	FileType_XML_MapUnit,
	FileType_XML_SaveData,
	FileType_XML_Database,
	FileType_XML_MapTree,
	FileType_Invalid
};

std::string GetFilename(const std::string& str);
FileTypes GetFiletype(const std::string& in_file, std::string& out_extension);
void PrintReaderError(const std::string data);
int ReaderWriteToFile(const std::string& in, const std::string& out, FileTypes in_type);

int main(int argc, char** argv)
{
	if (argc <= 1)
	{
		std::cerr << "Lcf2Xml - Converts RPG Maker 2k/2k3 Files to XML and vice versa" << std::endl;
		std::cerr << "Usage: lcf2xml [FILE] [OUTFILE]" << std::endl;
		//std::cerr << "If OUTFILE is missing the resulting file is named FILE with the extension replaced" << std::endl;
		return 1;
	}

	std::string infile;
	std::string outfile;

	infile = argv[1];

	FileTypes type;
	std::string extension;

	if (argc >= 3)
	{
		// OUTFILE
		outfile = argv[2];
		type = GetFiletype(infile, extension);
	}
	else
	{
		// No OUTFILE, add extension based on detected filetype
		outfile = GetFilename(infile);
		type = GetFiletype(infile, extension);
		outfile += extension;
	}

	return ReaderWriteToFile(infile, outfile, type);
}

/** Returns the filename (without extension). */
std::string GetFilename(const std::string& str)
{
	std::string s = str;
#ifdef _WIN32
	std::replace(s.begin(), s.end(), '\\', '/');
#endif
	// Extension
	size_t found = s.find_last_of(".");
	if (found != std::string::npos)
	{
		s = s.substr(0, found);
	}

	// Filename
	found = s.find_last_of("/");
	if (found == std::string::npos)
	{
		return s;
	}

	s = s.substr(found + 1);
	return s;
}

/** Uses heuristics to detect the file type. */
FileTypes GetFiletype(const std::string& in_file, std::string& out_extension)
{
	std::ifstream in(in_file.c_str());

	char buf[128];
	memset(buf, '\0', 128);

	in.seekg(1, std::ios::beg);
	in.read(buf, 10);
	std::string input(buf);

	out_extension = ".xml";
	if (input == "LcfDataBas") {
		return FileType_LCF_Database;
	} else if (input == "LcfMapTree") {
		return FileType_LCF_MapTree;
	} else if (input == "LcfSaveDat") {
		return FileType_LCF_SaveData;
	} else if (input == "LcfMapUnit") {
		return FileType_LCF_MapUnit;
	} else if (input == "?xml versi") {
		in.read(buf, 128);
		std::string in(buf);

		size_t pos = in.find('<');
		if (pos != std::string::npos)
		{
			in = in.substr(pos + 1, 3);
			if (in == "LDB") {
				out_extension = ".ldb";
				return FileType_XML_Database;
			} else if (in == "LMT") {
				out_extension = ".lmt";
				return FileType_XML_MapTree;
			} else if (in == "LSD") {
				out_extension = ".lsd";
				return FileType_XML_SaveData;
			} else if (in == "LMU") {
				out_extension = ".lmu";
				return FileType_XML_MapUnit;
			}
		}
	}

	out_extension = "";
	return FileType_Invalid;
}

/** Utility func for errors. */
void PrintReaderError(const std::string data)
{
	std::cerr << data << " error: " << LcfReader::GetError() << std::endl;
}

#define LCFXML_ERROR(cond, text) \
	if (cond) {\
		PrintReaderError(text);\
		return 2;\
	}

/** Takes data from in and writes converted data into out using libreaders. */
int ReaderWriteToFile(const std::string& in, const std::string& out, FileTypes in_type)
{
	switch (in_type)
	{
		case FileType_LCF_MapUnit:
		{
			std::auto_ptr<RPG::Map> file = LMU_Reader::Load(in);
			LCFXML_ERROR(file.get() == NULL, "LMU load");
			LCFXML_ERROR(!LMU_Reader::SaveXml(out, *file), "LMU XML save");
			break;
		}
		case FileType_LCF_SaveData:
		{
			std::auto_ptr<RPG::Save> file = LSD_Reader::Load(in);
			LCFXML_ERROR(file.get() == NULL, "LSD load");
			LCFXML_ERROR(!LSD_Reader::SaveXml(out, *file), "LSD XML save");
			break;
		}
		case FileType_LCF_Database:
		{
			LCFXML_ERROR(!LDB_Reader::Load(in), "LDB load");
			LCFXML_ERROR(!LDB_Reader::SaveXml(out), "LDB XML save");
			break;
		}
		case FileType_LCF_MapTree:
		{
			LCFXML_ERROR(!LMT_Reader::Load(in), "LMT load");
			LCFXML_ERROR(!LMT_Reader::SaveXml(out), "LMT XML save");
			break;
		}
		case FileType_XML_MapUnit:
		{
			std::auto_ptr<RPG::Map> file = LMU_Reader::LoadXml(in);
			LCFXML_ERROR(file.get() == NULL, "LMU XML load");
			LCFXML_ERROR(!LMU_Reader::Save(out, *file), "LMU save");
			break;
		}
		case FileType_XML_SaveData:
		{
			std::auto_ptr<RPG::Save> file = LSD_Reader::LoadXml(in);
			LCFXML_ERROR(file.get() == NULL, "LSD XML load");
			LCFXML_ERROR(!LSD_Reader::Save(out, *file), "LSD save");
			break;
		}
		case FileType_XML_Database:
		{
			LCFXML_ERROR(!LDB_Reader::LoadXml(in), "LDB XML load");
			LCFXML_ERROR(!LDB_Reader::Save(out), "LDB save");
			break;
		}
		case FileType_XML_MapTree:
		{
			LCFXML_ERROR(!LMT_Reader::LoadXml(in), "LMT XML load");
			LCFXML_ERROR(!LMT_Reader::Save(out), "LMT save");
			break;
		}
		case FileType_Invalid:
		{
			std::cerr << in << " unsupported" << std::endl;
			return 2;
		}
	}

	return 0;
}
<|endoftext|>


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

#include "sql/sql.h"
#include "sql/SQL_Connection.h"
#include "sql/SQL_Statement.h"
#include "sql/SQL_Pools.h"

#if defined PLUGIN_SUPPORTS_MYSQL
	#include "sql/mysql/mysql.h"
#endif

#if defined PLUGIN_SUPPORTS_PGSQL
	#include "sql/pgsql/pgsql.h"
#endif

#include "Logger.h"
#include "Natives.h"

#include "main.h"

extern void *pAMXFunctions;

const AMX_NATIVE_INFO NATIVES[] = {
	{"sql_debug", Natives::sql_debug},
	{"sql_connect", Natives::sql_connect},
	{"sql_disconnect", Natives::sql_disconnect},
	{"sql_wait", Natives::sql_wait},
	{"sql_set_charset", Natives::sql_set_charset},
	{"sql_get_charset", Natives::sql_get_charset},
	{"sql_ping", Natives::sql_ping},
	{"sql_get_stat", Natives::sql_get_stat},
	{"sql_escape_string", Natives::sql_escape_string},
	{"sql_format", Natives::sql_format},
	{"sql_query", Natives::sql_query},
	{"sql_store_result", Natives::sql_store_result},
	{"sql_free_result", Natives::sql_free_result},
	{"sql_insert_id", Natives::sql_insert_id},
	{"sql_affected_rows", Natives::sql_affected_rows},
	{"sql_error", Natives::sql_error},
	{"sql_error_string", Natives::sql_error_string},
	{"sql_num_rows", Natives::sql_num_rows},
	{"sql_num_fields", Natives::sql_num_fields},
	{"sql_next_result", Natives::sql_next_result},
	{"sql_field_name", Natives::sql_field_name},
	{"sql_fetch_row", Natives::sql_fetch_row},
	// Polymorphic natives.
	{"sql_next_row", Natives::sql_next_row},
	{"sql_get_field", Natives::sql_get_field},
	{"sql_get_field_assoc", Natives::sql_get_field_assoc},
	{"sql_get_field_int", Natives::sql_get_field_int},
	{"sql_get_field_assoc_int", Natives::sql_get_field_assoc_int},
	{"sql_get_field_float", Natives::sql_get_field_float},
	{"sql_get_field_assoc_float", Natives::sql_get_field_assoc_float},
	// The extended version (includes a `row` parameter).
	{"sql_get_field_ex", Natives::sql_get_field},
	{"sql_get_field_assoc_ex", Natives::sql_get_field_assoc},
	{"sql_get_field_int_ex", Natives::sql_get_field_int},
	{"sql_get_field_assoc_int_ex", Natives::sql_get_field_assoc_int},
	{"sql_get_field_float_ex", Natives::sql_get_field_float},
	{"sql_get_field_assoc_float_ex", Natives::sql_get_field_assoc_float},
	{NULL, NULL}
};

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES | SUPPORTS_PROCESS_TICK;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	Logger::logprintf = (logprintf_t) ppData[PLUGIN_DATA_LOGPRINTF];
	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
	#ifdef PLUGIN_SUPPORTS_MYSQL
		if (mysql_library_init(0, NULL, NULL)) {
			Logger::logprintf("  >> Coudln't initalize the MySQL library (libmysql.dll). It's probably missing.");
			exit(0);
			return false;
		}
	#endif
	Logger::logprintf("  >> SQL plugin " PLUGIN_VERSION " successfully loaded.");
	#ifdef PLUGIN_SUPPORTS_MYSQL
		Logger::logprintf("      + MySQL support is enabled.");
	#endif
	#ifdef PLUGIN_SUPPORTS_PGSQL
		Logger::logprintf("      + PostgreSQL support is enabled.");
	#endif
	return true;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	return amx_Register(amx, NATIVES, -1);
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	for (connectionsMap_t::iterator it = SQL_Pools::connections.begin(), next = it, end = SQL_Pools::connections.end(); it != end; it = next) {
		++next;
		SQL_Connection *conn = it->second;
		if (conn->amx == amx) {
			SQL_Pools::connections.erase(it);
			conn->stopWorker();
			delete conn;
		}
	}
	for (statementsMap_t::iterator it = SQL_Pools::statements.begin(), next = it, end = SQL_Pools::statements.end(); it != end; it = next) {
		++next;
		SQL_Statement *stmt = it->second;
		if (stmt->amx == amx) {
			SQL_Pools::statements.erase(it);
			delete stmt;
		}
	}
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	#ifdef PLUGIN_SUPPORTS_MYSQL
		mysql_library_end();
	#endif
	Logger::logprintf("[plugin.sql] Plugin succesfully unloaded!");
}

PLUGIN_EXPORT void PLUGIN_CALL ProcessTick() {
	for (statementsMap_t::iterator it = SQL_Pools::statements.begin(), next = it, end = SQL_Pools::statements.end(); it != end; it = next) {
		++next;
		SQL_Statement *stmt = it->second;
		if ((stmt->flags & STATEMENT_FLAGS_THREADED) && (stmt->status == STATEMENT_STATUS_EXECUTED)) {
			Logger::log(LOG_DEBUG, "ProccessTick: Executing query callback (stmt->id = %d, stmt->error = %d, stmt->callback = %s)...", stmt->id, stmt->error, stmt->callback);
			int id = stmt->id;
			stmt->executeCallback();
			if (!SQL_Pools::isValidStatement(id)) {
				continue;
			}
		}
		if ((!SQL_Pools::isValidConnection(stmt->connectionId)) || (stmt->status == STATEMENT_STATUS_PROCESSED)) {
			Logger::log(LOG_DEBUG, "ProccessTick: Erasing query (stmt->id = %d)...", stmt->id);
			SQL_Pools::statements.erase(it);
			delete stmt;
		}
	}
}
<commit_msg>Fixed a typo.<commit_after>/**
 * Copyright (c) 2013, Dan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "sql/sql.h"
#include "sql/SQL_Connection.h"
#include "sql/SQL_Statement.h"
#include "sql/SQL_Pools.h"

#if defined PLUGIN_SUPPORTS_MYSQL
	#include "sql/mysql/mysql.h"
#endif

#if defined PLUGIN_SUPPORTS_PGSQL
	#include "sql/pgsql/pgsql.h"
#endif

#include "Logger.h"
#include "Natives.h"

#include "main.h"

extern void *pAMXFunctions;

const AMX_NATIVE_INFO NATIVES[] = {
	{"sql_debug", Natives::sql_debug},
	{"sql_connect", Natives::sql_connect},
	{"sql_disconnect", Natives::sql_disconnect},
	{"sql_wait", Natives::sql_wait},
	{"sql_set_charset", Natives::sql_set_charset},
	{"sql_get_charset", Natives::sql_get_charset},
	{"sql_ping", Natives::sql_ping},
	{"sql_get_stat", Natives::sql_get_stat},
	{"sql_escape_string", Natives::sql_escape_string},
	{"sql_format", Natives::sql_format},
	{"sql_query", Natives::sql_query},
	{"sql_store_result", Natives::sql_store_result},
	{"sql_free_result", Natives::sql_free_result},
	{"sql_insert_id", Natives::sql_insert_id},
	{"sql_affected_rows", Natives::sql_affected_rows},
	{"sql_error", Natives::sql_error},
	{"sql_error_string", Natives::sql_error_string},
	{"sql_num_rows", Natives::sql_num_rows},
	{"sql_num_fields", Natives::sql_num_fields},
	{"sql_next_result", Natives::sql_next_result},
	{"sql_field_name", Natives::sql_field_name},
	{"sql_fetch_row", Natives::sql_fetch_row},
	// Polymorphic natives.
	{"sql_next_row", Natives::sql_next_row},
	{"sql_get_field", Natives::sql_get_field},
	{"sql_get_field_assoc", Natives::sql_get_field_assoc},
	{"sql_get_field_int", Natives::sql_get_field_int},
	{"sql_get_field_assoc_int", Natives::sql_get_field_assoc_int},
	{"sql_get_field_float", Natives::sql_get_field_float},
	{"sql_get_field_assoc_float", Natives::sql_get_field_assoc_float},
	// The extended version (includes a `row` parameter).
	{"sql_get_field_ex", Natives::sql_get_field},
	{"sql_get_field_assoc_ex", Natives::sql_get_field_assoc},
	{"sql_get_field_int_ex", Natives::sql_get_field_int},
	{"sql_get_field_assoc_int_ex", Natives::sql_get_field_assoc_int},
	{"sql_get_field_float_ex", Natives::sql_get_field_float},
	{"sql_get_field_assoc_float_ex", Natives::sql_get_field_assoc_float},
	{NULL, NULL}
};

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES | SUPPORTS_PROCESS_TICK;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	Logger::logprintf = (logprintf_t) ppData[PLUGIN_DATA_LOGPRINTF];
	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
	#ifdef PLUGIN_SUPPORTS_MYSQL
		if (mysql_library_init(0, NULL, NULL)) {
			Logger::logprintf("  >> Couldn't initalize the MySQL library (libmysql.dll). It's probably missing.");
			exit(0);
			return false;
		}
	#endif
	Logger::logprintf("  >> SQL plugin " PLUGIN_VERSION " successfully loaded.");
	#ifdef PLUGIN_SUPPORTS_MYSQL
		Logger::logprintf("      + MySQL support is enabled.");
	#endif
	#ifdef PLUGIN_SUPPORTS_PGSQL
		Logger::logprintf("      + PostgreSQL support is enabled.");
	#endif
	return true;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	return amx_Register(amx, NATIVES, -1);
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	for (connectionsMap_t::iterator it = SQL_Pools::connections.begin(), next = it, end = SQL_Pools::connections.end(); it != end; it = next) {
		++next;
		SQL_Connection *conn = it->second;
		if (conn->amx == amx) {
			SQL_Pools::connections.erase(it);
			conn->stopWorker();
			delete conn;
		}
	}
	for (statementsMap_t::iterator it = SQL_Pools::statements.begin(), next = it, end = SQL_Pools::statements.end(); it != end; it = next) {
		++next;
		SQL_Statement *stmt = it->second;
		if (stmt->amx == amx) {
			SQL_Pools::statements.erase(it);
			delete stmt;
		}
	}
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	#ifdef PLUGIN_SUPPORTS_MYSQL
		mysql_library_end();
	#endif
	Logger::logprintf("[plugin.sql] Plugin succesfully unloaded!");
}

PLUGIN_EXPORT void PLUGIN_CALL ProcessTick() {
	for (statementsMap_t::iterator it = SQL_Pools::statements.begin(), next = it, end = SQL_Pools::statements.end(); it != end; it = next) {
		++next;
		SQL_Statement *stmt = it->second;
		if ((stmt->flags & STATEMENT_FLAGS_THREADED) && (stmt->status == STATEMENT_STATUS_EXECUTED)) {
			Logger::log(LOG_DEBUG, "ProccessTick: Executing query callback (stmt->id = %d, stmt->error = %d, stmt->callback = %s)...", stmt->id, stmt->error, stmt->callback);
			int id = stmt->id;
			stmt->executeCallback();
			if (!SQL_Pools::isValidStatement(id)) {
				continue;
			}
		}
		if ((!SQL_Pools::isValidConnection(stmt->connectionId)) || (stmt->status == STATEMENT_STATUS_PROCESSED)) {
			Logger::log(LOG_DEBUG, "ProccessTick: Erasing query (stmt->id = %d)...", stmt->id);
			SQL_Pools::statements.erase(it);
			delete stmt;
		}
	}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <numeric>
#include <algorithm>
#include <vector>
#include <map>
#include <chrono>
#include <memory>
#include <typeinfo>

#include <hpx/hpx.hpp>
#include <hpx/hpx_init.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/iostreams.hpp>
#include <hpx/include/serialization.hpp>

#include "incumbent_component.hpp"
#include "workqueue_component.hpp"

#include "DimacsParser.hpp"
#include "BitGraph.hpp"
#include "BitSet.hpp"

// 64 bit words
// 8 words covers 400 vertices
// Later we can specialise this at compile time
#define NWORDS 8

// Forward action decls
namespace graph {
  template<unsigned n_words_>
  auto maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) -> void;

  std::atomic<int> globalBound(0);
  auto updateBound(int newBound) -> void;
  auto broadcastBound(int newBound) -> void;

}
HPX_PLAIN_ACTION(graph::maxcliqueTask<NWORDS>, maxcliqueTask400Action)
HPX_PLAIN_ACTION(graph::updateBound, updateBoundAction)
HPX_PLAIN_ACTION(graph::broadcastBound, broadcastBoundAction)

// For distributed promises
HPX_REGISTER_ACTION(hpx::lcos::base_lco_with_value<int>::set_value_action, set_value_action_int);

namespace graph {
  // Order a graphFromFile and return an ordered graph alongside a map to invert
  // the vertex numbering at the end.
  template<unsigned n_words_>
  auto orderGraphFromFile(const dimacs::GraphFromFile & g, std::map<int,int> & inv) -> BitGraph<n_words_> {
    std::vector<int> order(g.first);
    std::iota(order.begin(), order.end(), 0);

    // Order by degree, tie break on number
    std::vector<int> degrees;
    std::transform(order.begin(), order.end(), std::back_inserter(degrees),
                    [&] (int v) { return g.second.find(v)->second.size(); });

    std::sort(order.begin(), order.end(),
            [&] (int a, int b) { return ! (degrees[a] < degrees[b] || (degrees[a] == degrees[b] && a > b)); });

    // Construct a new graph with this new ordering
    BitGraph<n_words_> graph;
    graph.resize(g.first);

    for (unsigned i = 0 ; i < g.first ; ++i)
      for (unsigned j = 0 ; j < g.first ; ++j)
        if (g.second.find(order[i])->second.count(order[j]))
          graph.add_edge(i, j);

    // Create inv map (maybe just return order?)
    for (int i = 0; i < order.size(); i++) {
      inv[i] = order[i];
    }

    return graph;
    }

  template<unsigned n_words_>
  auto colour_class_order(const BitGraph<n_words_> & graph,
                          const BitSet<n_words_> & p,
                          std::array<unsigned, n_words_ * bits_per_word> & p_order,
                          std::array<unsigned, n_words_ * bits_per_word> & p_bounds) -> void {
    BitSet<n_words_> p_left = p; // not coloured yet
    unsigned colour = 0;         // current colour
    unsigned i = 0;              // position in p_bounds

    // while we've things left to colour
    while (! p_left.empty()) {
      // next colour
      ++colour;
      // things that can still be given this colour
      BitSet<n_words_> q = p_left;

      // while we can still give something this colour
      while (! q.empty()) {
        // first thing we can colour
        int v = q.first_set_bit();
        p_left.unset(v);
        q.unset(v);

        // can't give anything adjacent to this the same colour
        graph.intersect_with_row_complement(v, q);

        // record in result
        p_bounds[i] = colour;
        p_order[i] = v;
        ++i;
      }
    }
  }

  template <unsigned n_words_>
  auto expand(const BitGraph<n_words_> & graph,
              const hpx::naming::id_type & incumbent,
              std::vector<unsigned> & c,
              BitSet<n_words_> & p) -> void {
    // initial colouring
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    // for each v in p... (v comes later)
    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      auto bnd = globalBound.load();
      if (c.size() + p_bounds[n] <= bnd)
        return;

      auto v = p_order[n];

      // consider taking v
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (c.size() > bnd) {
          std::set<int> members;
          for (auto & v : c) {
            members.insert(v);
          }

          // Fire and forget updates
          hpx::apply<globalBound::incumbent::updateBound_action>(incumbent, c.size(), members);
          hpx::async<broadcastBoundAction>(hpx::find_here(), c.size()).get();
      } else {
        expand(graph, incumbent, c, new_p);
      }

      // now consider not taking v
      c.pop_back();
      p.unset(v);
    }
  }

  template<unsigned n_words_>
  auto spawnTasks(const BitGraph<n_words_> & graph,
                  std::uint64_t spawnDepth,
                  std::vector<unsigned> c,
                  BitSet<n_words_> p,
                  hpx::naming::id_type workqueue,
                  hpx::naming::id_type incumbent,
                  std::vector<hpx::future<int>> & futures) -> void {
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      auto v = p_order[n];
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (spawnDepth == 0) {
        auto promise = std::shared_ptr<hpx::promise<int>>(new hpx::promise<int>());
        auto f = promise->get_future();
        auto promise_id = promise->get_id();

        futures.push_back(std::move(f));

        hpx::util::function<void(hpx::naming::id_type)> task = hpx::util::bind(maxcliqueTask400Action(), _1, graph, incumbent, c, new_p, promise_id);
        hpx::apply<workstealing::workqueue::addWork_action>(workqueue, task);
      } else {
        spawnTasks(graph, spawnDepth - 1, c, new_p, workqueue, incumbent, futures);
      }

      c.pop_back();
      p.unset(v);
    }
  }

  template<unsigned n_words_>
  void maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) {
    expand(graph, incumbent, c, p);
    hpx::apply<hpx::lcos::base_lco_with_value<int>::set_value_action>(promise, 1);
    return;
  }

  // Atomically update the global bound on all localities
  auto broadcastBound(int newBound) -> void {
    auto localities = hpx::find_all_localities();
    for (auto const & node : localities) {
      hpx::apply<updateBoundAction>(node, newBound);
    }
  }

  auto updateBound(int newBound) -> void {
    while(true) {
      auto curBnd = globalBound.load();
      if (newBound < curBnd) {
        break;
      }

      if (globalBound.compare_exchange_weak(curBnd, newBound)) {
        break;
      }
    }
  }

  template<unsigned n_words_>
  auto runMaxClique(const BitGraph<n_words_> & graph, std::uint64_t spawnDepth, hpx::naming::id_type incumbent, hpx::naming::id_type workqueue) -> void {
    BitSet<n_words_> p;
    p.resize(graph.size());
    p.set_all();

    std::vector<hpx::future<int>> futures;
    std::vector<unsigned> c;
    spawnTasks(graph, spawnDepth, c, p, workqueue, incumbent, futures);
    hpx::wait_all(futures);
  }
}

void scheduler(hpx::naming::id_type workqueue) {
  auto threads = hpx::get_os_thread_count() == 1 ? 1 : hpx::get_os_thread_count() - 1;
  hpx::threads::executors::local_queue_executor scheduler(threads);

  // Debugging
  std::cout << "Running with: " << threads << " scheduler threads" << std::endl;

  bool running = true;
  while (running) {
    auto pending = scheduler.num_pending_closures();
    if (pending < threads) {
      auto task = hpx::async<workstealing::workqueue::steal_action>(workqueue).get();
      if (task) {
        auto t = hpx::util::bind(task, hpx::find_here());
        scheduler.add(t);
      }
    } else {
      hpx::this_thread::suspend();
    }
  }
}
HPX_PLAIN_ACTION(scheduler, schedulerAction)

int hpx_main(boost::program_options::variables_map & opts) {
  auto inputFile = opts["input-file"].as<std::string>();
  if (inputFile.empty()) {
    hpx::finalize();
    return EXIT_FAILURE;
  }

  auto gFile = dimacs::read_dimacs(inputFile);

  // Order the graph (keep a hold of the map)
  std::map<int, int> invMap;
  auto graph = graph::orderGraphFromFile<NWORDS>(gFile, invMap);

  // Run Maxclique
  auto incumbent = hpx::new_<globalBound::incumbent>(hpx::find_here()).get();
  auto workqueue = hpx::new_<workstealing::workqueue>(hpx::find_here()).get();

  // Start a scheduler on each node
  auto localities = hpx::find_all_localities();
  for (auto const & node : localities) {
    // Can't use async here since the scheduler never returns
    hpx::apply<schedulerAction>(node, workqueue);
  }

  auto spawnDepth = opts["spawn-depth"].as<std::uint64_t>();
  auto start_time = std::chrono::steady_clock::now();
  graph::runMaxClique(graph, spawnDepth, incumbent, workqueue);
  auto overall_time = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - start_time);

  // Output result
  hpx::cout << "Size: " << hpx::async<globalBound::incumbent::getBound_action>(incumbent).get() << hpx::endl;

  auto members = hpx::async<globalBound::incumbent::getMembers_action>(incumbent).get();
  hpx::cout << "Members: " << hpx::endl;
  for (auto const& m : members) {
    hpx::cout << invMap[m] + 1 << " ";
  }
  hpx::cout << hpx::endl << hpx::flush;

  hpx::cout << "cpu = " << overall_time.count() << std::endl;

  // TODO: A nicer termination
  //hpx::finalize();
  hpx::this_thread::suspend(2000);
  hpx::terminate();
}

int main (int argc, char* argv[]) {
  boost::program_options::options_description
    desc_commandline("Usage: " HPX_APPLICATION_STRING " [options]");

  desc_commandline.add_options()
    ( "spawn-depth,d",
      boost::program_options::value<std::uint64_t>()->default_value(1),
      "Depth in the tree to spawn at"
    )
    ( "input-file,f",
      boost::program_options::value<std::string>(),
      "DIMACS formatted input graph"
    );

  return hpx::init(desc_commandline, argc, argv);
}

<commit_msg>Make sure the incumbent is updated before finishing<commit_after>#include <iostream>
#include <numeric>
#include <algorithm>
#include <vector>
#include <map>
#include <chrono>
#include <memory>
#include <typeinfo>

#include <hpx/hpx.hpp>
#include <hpx/hpx_init.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/iostreams.hpp>
#include <hpx/include/serialization.hpp>

#include "incumbent_component.hpp"
#include "workqueue_component.hpp"

#include "DimacsParser.hpp"
#include "BitGraph.hpp"
#include "BitSet.hpp"

// 64 bit words
// 8 words covers 400 vertices
// Later we can specialise this at compile time
#define NWORDS 8

// Forward action decls
namespace graph {
  template<unsigned n_words_>
  auto maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) -> void;

  std::atomic<int> globalBound(0);
  auto updateBound(int newBound) -> void;
  auto broadcastBound(int newBound) -> void;

}
HPX_PLAIN_ACTION(graph::maxcliqueTask<NWORDS>, maxcliqueTask400Action)
HPX_PLAIN_ACTION(graph::updateBound, updateBoundAction)
HPX_PLAIN_ACTION(graph::broadcastBound, broadcastBoundAction)

// For distributed promises
HPX_REGISTER_ACTION(hpx::lcos::base_lco_with_value<int>::set_value_action, set_value_action_int);

namespace graph {
  // Order a graphFromFile and return an ordered graph alongside a map to invert
  // the vertex numbering at the end.
  template<unsigned n_words_>
  auto orderGraphFromFile(const dimacs::GraphFromFile & g, std::map<int,int> & inv) -> BitGraph<n_words_> {
    std::vector<int> order(g.first);
    std::iota(order.begin(), order.end(), 0);

    // Order by degree, tie break on number
    std::vector<int> degrees;
    std::transform(order.begin(), order.end(), std::back_inserter(degrees),
                    [&] (int v) { return g.second.find(v)->second.size(); });

    std::sort(order.begin(), order.end(),
            [&] (int a, int b) { return ! (degrees[a] < degrees[b] || (degrees[a] == degrees[b] && a > b)); });

    // Construct a new graph with this new ordering
    BitGraph<n_words_> graph;
    graph.resize(g.first);

    for (unsigned i = 0 ; i < g.first ; ++i)
      for (unsigned j = 0 ; j < g.first ; ++j)
        if (g.second.find(order[i])->second.count(order[j]))
          graph.add_edge(i, j);

    // Create inv map (maybe just return order?)
    for (int i = 0; i < order.size(); i++) {
      inv[i] = order[i];
    }

    return graph;
    }

  template<unsigned n_words_>
  auto colour_class_order(const BitGraph<n_words_> & graph,
                          const BitSet<n_words_> & p,
                          std::array<unsigned, n_words_ * bits_per_word> & p_order,
                          std::array<unsigned, n_words_ * bits_per_word> & p_bounds) -> void {
    BitSet<n_words_> p_left = p; // not coloured yet
    unsigned colour = 0;         // current colour
    unsigned i = 0;              // position in p_bounds

    // while we've things left to colour
    while (! p_left.empty()) {
      // next colour
      ++colour;
      // things that can still be given this colour
      BitSet<n_words_> q = p_left;

      // while we can still give something this colour
      while (! q.empty()) {
        // first thing we can colour
        int v = q.first_set_bit();
        p_left.unset(v);
        q.unset(v);

        // can't give anything adjacent to this the same colour
        graph.intersect_with_row_complement(v, q);

        // record in result
        p_bounds[i] = colour;
        p_order[i] = v;
        ++i;
      }
    }
  }

  template <unsigned n_words_>
  auto expand(const BitGraph<n_words_> & graph,
              const hpx::naming::id_type & incumbent,
              std::vector<unsigned> & c,
              BitSet<n_words_> & p) -> void {
    // initial colouring
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    // for each v in p... (v comes later)
    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      auto bnd = globalBound.load();
      if (c.size() + p_bounds[n] <= bnd)
        return;

      auto v = p_order[n];

      // consider taking v
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (c.size() > bnd) {
          std::set<int> members;
          for (auto & v : c) {
            members.insert(v);
          }
          hpx::async<globalBound::incumbent::updateBound_action>(incumbent, c.size(), members).get();
          hpx::async<broadcastBoundAction>(hpx::find_here(), c.size()).get();
      } else {
        expand(graph, incumbent, c, new_p);
      }

      // now consider not taking v
      c.pop_back();
      p.unset(v);
    }
  }

  template<unsigned n_words_>
  auto spawnTasks(const BitGraph<n_words_> & graph,
                  std::uint64_t spawnDepth,
                  std::vector<unsigned> c,
                  BitSet<n_words_> p,
                  hpx::naming::id_type workqueue,
                  hpx::naming::id_type incumbent,
                  std::vector<hpx::future<int>> & futures) -> void {
    std::array<unsigned, n_words_ * bits_per_word> p_order;
    std::array<unsigned, n_words_ * bits_per_word> p_bounds;
    colour_class_order(graph, p, p_order, p_bounds);

    for (int n = p.popcount() - 1 ; n >= 0 ; --n) {
      auto v = p_order[n];
      c.push_back(v);

      // filter p to contain vertices adjacent to v
      BitSet<n_words_> new_p = p;
      graph.intersect_with_row(v, new_p);

      if (spawnDepth == 0) {
        auto promise = std::shared_ptr<hpx::promise<int>>(new hpx::promise<int>());
        auto f = promise->get_future();
        auto promise_id = promise->get_id();

        futures.push_back(std::move(f));

        hpx::util::function<void(hpx::naming::id_type)> task = hpx::util::bind(maxcliqueTask400Action(), _1, graph, incumbent, c, new_p, promise_id);
        hpx::apply<workstealing::workqueue::addWork_action>(workqueue, task);
      } else {
        spawnTasks(graph, spawnDepth - 1, c, new_p, workqueue, incumbent, futures);
      }

      c.pop_back();
      p.unset(v);
    }
  }

  template<unsigned n_words_>
  void maxcliqueTask(const BitGraph<n_words_> graph, hpx::naming::id_type incumbent, std::vector<unsigned> c, BitSet<n_words_> p, hpx::naming::id_type promise) {
    expand(graph, incumbent, c, p);
    hpx::apply<hpx::lcos::base_lco_with_value<int>::set_value_action>(promise, 1);
    return;
  }

  // Atomically update the global bound on all localities
  auto broadcastBound(int newBound) -> void {
    auto localities = hpx::find_all_localities();
    for (auto const & node : localities) {
      hpx::apply<updateBoundAction>(node, newBound);
    }
  }

  auto updateBound(int newBound) -> void {
    while(true) {
      auto curBnd = globalBound.load();
      if (newBound < curBnd) {
        break;
      }

      if (globalBound.compare_exchange_weak(curBnd, newBound)) {
        break;
      }
    }
  }

  template<unsigned n_words_>
  auto runMaxClique(const BitGraph<n_words_> & graph, std::uint64_t spawnDepth, hpx::naming::id_type incumbent, hpx::naming::id_type workqueue) -> void {
    BitSet<n_words_> p;
    p.resize(graph.size());
    p.set_all();

    std::vector<hpx::future<int>> futures;
    std::vector<unsigned> c;
    spawnTasks(graph, spawnDepth, c, p, workqueue, incumbent, futures);
    hpx::wait_all(futures);
  }
}

void scheduler(hpx::naming::id_type workqueue) {
  auto threads = hpx::get_os_thread_count() == 1 ? 1 : hpx::get_os_thread_count() - 1;
  hpx::threads::executors::local_queue_executor scheduler(threads);

  // Debugging
  std::cout << "Running with: " << threads << " scheduler threads" << std::endl;

  bool running = true;
  while (running) {
    auto pending = scheduler.num_pending_closures();
    if (pending < threads) {
      auto task = hpx::async<workstealing::workqueue::steal_action>(workqueue).get();
      if (task) {
        auto t = hpx::util::bind(task, hpx::find_here());
        scheduler.add(t);
      }
    } else {
      hpx::this_thread::suspend();
    }
  }
}
HPX_PLAIN_ACTION(scheduler, schedulerAction)

int hpx_main(boost::program_options::variables_map & opts) {
  auto inputFile = opts["input-file"].as<std::string>();
  if (inputFile.empty()) {
    hpx::finalize();
    return EXIT_FAILURE;
  }

  auto gFile = dimacs::read_dimacs(inputFile);

  // Order the graph (keep a hold of the map)
  std::map<int, int> invMap;
  auto graph = graph::orderGraphFromFile<NWORDS>(gFile, invMap);

  // Run Maxclique
  auto incumbent = hpx::new_<globalBound::incumbent>(hpx::find_here()).get();
  auto workqueue = hpx::new_<workstealing::workqueue>(hpx::find_here()).get();

  // Start a scheduler on each node
  auto localities = hpx::find_all_localities();
  for (auto const & node : localities) {
    // Can't use async here since the scheduler never returns
    hpx::apply<schedulerAction>(node, workqueue);
  }

  auto spawnDepth = opts["spawn-depth"].as<std::uint64_t>();
  auto start_time = std::chrono::steady_clock::now();
  graph::runMaxClique(graph, spawnDepth, incumbent, workqueue);
  auto overall_time = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - start_time);

  // Output result
  hpx::cout << "Size: " << hpx::async<globalBound::incumbent::getBound_action>(incumbent).get() << hpx::endl;

  auto members = hpx::async<globalBound::incumbent::getMembers_action>(incumbent).get();
  hpx::cout << "Members: " << hpx::endl;
  for (auto const& m : members) {
    hpx::cout << invMap[m] + 1 << " ";
  }
  hpx::cout << hpx::endl << hpx::flush;

  hpx::cout << "cpu = " << overall_time.count() << std::endl;

  // TODO: A nicer termination
  //hpx::finalize();
  hpx::this_thread::suspend(2000);
  hpx::terminate();
}

int main (int argc, char* argv[]) {
  boost::program_options::options_description
    desc_commandline("Usage: " HPX_APPLICATION_STRING " [options]");

  desc_commandline.add_options()
    ( "spawn-depth,d",
      boost::program_options::value<std::uint64_t>()->default_value(1),
      "Depth in the tree to spawn at"
    )
    ( "input-file,f",
      boost::program_options::value<std::string>(),
      "DIMACS formatted input graph"
    );

  return hpx::init(desc_commandline, argc, argv);
}

<|endoftext|>


<commit_before>#include <chrono>
#include <future>
#include <iostream>
#include <fstream>
#include <vector>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>

#include "json.hpp"

using json = nlohmann::json;

class ElapsedTime {
public:
    void start() {
        start_ = std::chrono::high_resolution_clock::now();
    }

    void stop() {
        const auto end = std::chrono::high_resolution_clock::now();
        duration_ = static_cast<unsigned>(std::chrono::duration_cast<std::chrono::milliseconds>(end - start_).count());
    }

    unsigned duration() const {
        return duration_;
    }
private:
    std::chrono::high_resolution_clock::time_point start_;
    unsigned duration_;
};

class Monitor {
public:
    bool run() {
        elapsedTime_.start();
        const bool result = execute();
        elapsedTime_.stop();
        return result;
    }

    const std::string& errorMessage() const {
        return errorMessage_;
    }

    unsigned duration() const {
        return elapsedTime_.duration();
    }

protected:
    virtual bool execute() = 0;

    std::string errorMessage_;

private:
    ElapsedTime elapsedTime_;
};

class WebsiteMonitor : public Monitor {
public:
    WebsiteMonitor(const std::string& url, unsigned timeout)
        : url_(url)
        , timeout_(timeout)
    {
    }

    virtual bool execute() override {
        extern bool HttpHead(const std::string& url, unsigned timeout, std::string& errorMessage);
        return HttpHead(url_, timeout_, errorMessage_);
    }

private:
    const std::string url_;
    const unsigned timeout_;
};

class ServiceMonitor : public Monitor {
public:
    ServiceMonitor(const std::string& host, unsigned port, unsigned timeout)
        : host_(host)
        , port_(std::to_string(port))
        , timeout_(timeout)
    {
    }

    virtual bool execute() override {
        struct ::addrinfo hints = {};
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;

        struct ::addrinfo *res = nullptr;
        const int getaddrinfo_error = ::getaddrinfo(host_.c_str(), port_.c_str(), &hints, &res);
        if (getaddrinfo_error != 0) {
            errorMessage_ = "Can't get address: " + std::string(::gai_strerror(getaddrinfo_error));
            return false;
        }

        struct Socket {
            int value = -1;
            ~Socket() {
                if (value > 0) {
                    (void)::close(value);
                }
            }
        };

        Socket socket;
        socket.value = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if (socket.value < 0) {
            errorMessage_ = "Can't create socket: " + std::string(::strerror(errno));
            return false;
        }

        if (::fcntl(socket.value, F_SETFL, O_NONBLOCK) != 0) {
            errorMessage_ = "Can't set to non-blocking: " + std::string(::strerror(errno));
            return false;
        }

        if (::connect(socket.value, res->ai_addr, res->ai_addrlen) == 0) {
            return true;
        }

        if (errno != EINPROGRESS) {
            errorMessage_ = "Can't connect: " + std::string(::strerror(errno));
            return false;
        }

        ::fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(socket.value, &rfds);

        struct ::timeval tv;
        tv.tv_sec = timeout_;
        tv.tv_usec = 0;

        const int retval = ::select(socket.value+1, nullptr, &rfds, nullptr, &tv);
        if (retval == -1) {
            errorMessage_ = "Select failed: " + std::string(::strerror(errno));
            return false;
        } else if (retval) {
            return FD_ISSET(socket.value, &rfds) != 0;
        }

        errorMessage_ = "Timed out";
        return false;
    }

private:
    const std::string host_;
    const std::string port_;
    const unsigned timeout_;
};

class Server {
public:
    using MonitorPtr = std::unique_ptr<Monitor>;

    Server(const std::string& name, MonitorPtr monitor)
        : name_(name)
        , monitor_(std::move(monitor))
    {
    }

    const std::string& name() const {
        return name_;
    }

    const MonitorPtr& monitor() const {
        return monitor_;
    }

    void setResult(bool result) {
        result_ = result;
    }

    bool result() const {
        return result_;
    }

    Server(const Server&) = delete;
    Server& operator=(const Server&) = delete;

    Server(Server&& other) = default;
    Server& operator=(Server&&) = default;

private:
    std::string name_;
    MonitorPtr monitor_;
    bool result_;
};

class ServerMonitor {
public:
    ServerMonitor(const json& config)
        : config_(config)
    {
    }

    bool run() {
        const unsigned timeout = 5;

        std::vector<Server> servers;
        for (const json& server : config_["servers"]) {
            const auto name = server["name"].get<std::string>();
            const auto end = server.end();

            const auto url = server.find("url");
            if (url != end) {
                servers.emplace_back(name, std::make_unique<WebsiteMonitor>(url->get<std::string>(), timeout));
                continue;
            }

            const auto host = server.find("host");
            const auto port = server.find("port");
            if (host != end && port != end) {
                servers.emplace_back(name, std::make_unique<ServiceMonitor>(host->get<std::string>(), port->get<unsigned>(), timeout));
            }
        }

        std::vector<std::future<void>> futures;

        ElapsedTime elapsedTime;

        elapsedTime.start();

        for (auto& server : servers) {
            futures.push_back(std::async(std::launch::async, [&server](){
                server.setResult(server.monitor()->run());
            }));
        }

        for (auto& future : futures) {
            future.get();
        }

        elapsedTime.stop();

        for (const auto& server : servers) {
            const auto& monitor = server.monitor();
            printf("%s: %d: %s (%u ms)\n", server.name().c_str(), server.result(), monitor->errorMessage().c_str(), monitor->duration());
        }

        printf("Total time: %u ms\n", elapsedTime.duration());

        return true;
    }

private:
    const json config_;
};

int main(int argc, const char * argv[]) {
    if (argc != 2) {
        printf("Missing config arg\n");
        return EXIT_FAILURE;
    }

    json config;

    try {
        std::ifstream filestream(argv[1]);
        if (!filestream.is_open()) {
            printf("Invalid file: %s\n", argv[1]);
            return EXIT_FAILURE;
        }
        filestream >> config;
    } catch (const std::exception& ex) {
        std::cout << "ERROR: JSON invalid (" << ex.what() << ")" << std::endl;
        return EXIT_FAILURE;
    }

    ServerMonitor mon(config);
    return mon.run() ? EXIT_SUCCESS : EXIT_FAILURE;
}
<commit_msg>Process errors as exceptions<commit_after>#include <chrono>
#include <future>
#include <iostream>
#include <fstream>
#include <vector>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>

#include "json.hpp"

using json = nlohmann::json;

class ElapsedTime {
public:
    void start() {
        start_ = std::chrono::high_resolution_clock::now();
    }

    void stop() {
        const auto end = std::chrono::high_resolution_clock::now();
        duration_ = static_cast<unsigned>(std::chrono::duration_cast<std::chrono::milliseconds>(end - start_).count());
    }

    unsigned duration() const {
        return duration_;
    }
private:
    std::chrono::high_resolution_clock::time_point start_;
    unsigned duration_;
};

class Monitor {
public:
    bool run() {
        elapsedTime_.start();
        const bool result = execute();
        elapsedTime_.stop();
        return result;
    }

    const std::string& errorMessage() const {
        return errorMessage_;
    }

    unsigned duration() const {
        return elapsedTime_.duration();
    }

protected:
    virtual bool execute() = 0;

    std::string errorMessage_;

private:
    ElapsedTime elapsedTime_;
};

class WebsiteMonitor : public Monitor {
public:
    WebsiteMonitor(const std::string& url, unsigned timeout)
        : url_(url)
        , timeout_(timeout)
    {
    }

    virtual bool execute() override {
        extern bool HttpHead(const std::string& url, unsigned timeout, std::string& errorMessage);
        return HttpHead(url_, timeout_, errorMessage_);
    }

private:
    const std::string url_;
    const unsigned timeout_;
};

class ServiceMonitor : public Monitor {
public:
    ServiceMonitor(const std::string& host, unsigned port, unsigned timeout)
        : host_(host)
        , port_(std::to_string(port))
        , timeout_(timeout)
    {
    }

    virtual bool execute() override {
        struct ::addrinfo hints = {};
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;

        struct ::addrinfo *res = nullptr;
        const int getaddrinfo_error = ::getaddrinfo(host_.c_str(), port_.c_str(), &hints, &res);
        if (getaddrinfo_error != 0) {
            errorMessage_ = "Can't get address: " + std::string(::gai_strerror(getaddrinfo_error));
            return false;
        }

        struct Socket {
            int value = -1;
            ~Socket() {
                if (value > 0) {
                    (void)::close(value);
                }
            }
        };

        Socket socket;
        socket.value = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if (socket.value < 0) {
            errorMessage_ = "Can't create socket: " + std::string(::strerror(errno));
            return false;
        }

        if (::fcntl(socket.value, F_SETFL, O_NONBLOCK) != 0) {
            errorMessage_ = "Can't set to non-blocking: " + std::string(::strerror(errno));
            return false;
        }

        if (::connect(socket.value, res->ai_addr, res->ai_addrlen) == 0) {
            return true;
        }

        if (errno != EINPROGRESS) {
            errorMessage_ = "Can't connect: " + std::string(::strerror(errno));
            return false;
        }

        ::fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(socket.value, &rfds);

        struct ::timeval tv;
        tv.tv_sec = timeout_;
        tv.tv_usec = 0;

        const int retval = ::select(socket.value+1, nullptr, &rfds, nullptr, &tv);
        if (retval == -1) {
            errorMessage_ = "Select failed: " + std::string(::strerror(errno));
            return false;
        } else if (retval) {
            return FD_ISSET(socket.value, &rfds) != 0;
        }

        errorMessage_ = "Timed out";
        return false;
    }

private:
    const std::string host_;
    const std::string port_;
    const unsigned timeout_;
};

class Server {
public:
    using MonitorPtr = std::unique_ptr<Monitor>;

    Server(const std::string& name, MonitorPtr monitor)
        : name_(name)
        , monitor_(std::move(monitor))
    {
    }

    const std::string& name() const {
        return name_;
    }

    const MonitorPtr& monitor() const {
        return monitor_;
    }

    void setResult(bool result) {
        result_ = result;
    }

    bool result() const {
        return result_;
    }

    Server(const Server&) = delete;
    Server& operator=(const Server&) = delete;

    Server(Server&& other) = default;
    Server& operator=(Server&&) = default;

private:
    std::string name_;
    MonitorPtr monitor_;
    bool result_;
};

class ServerMonitor {
public:
    ServerMonitor(const json& config)
        : config_(config)
    {
    }

    void run() {
        const unsigned timeout = 5;

        std::vector<Server> servers;
        for (const json& server : config_["servers"]) {
            const auto name = server["name"].get<std::string>();
            const auto end = server.end();

            const auto url = server.find("url");
            if (url != end) {
                servers.emplace_back(name, std::make_unique<WebsiteMonitor>(url->get<std::string>(), timeout));
                continue;
            }

            const auto host = server.find("host");
            const auto port = server.find("port");
            if (host != end && port != end) {
                servers.emplace_back(name, std::make_unique<ServiceMonitor>(host->get<std::string>(), port->get<unsigned>(), timeout));
            }
        }

        std::vector<std::future<void>> futures;

        ElapsedTime elapsedTime;

        elapsedTime.start();

        for (auto& server : servers) {
            futures.push_back(std::async(std::launch::async, [&server](){
                server.setResult(server.monitor()->run());
            }));
        }

        for (auto& future : futures) {
            future.get();
        }

        elapsedTime.stop();

        for (const auto& server : servers) {
            const auto& monitor = server.monitor();
            printf("%s: %d: %s (%u ms)\n", server.name().c_str(), server.result(), monitor->errorMessage().c_str(), monitor->duration());
        }

        printf("Total time: %u ms\n", elapsedTime.duration());
    }

private:
    const json config_;
};

int main(int argc, const char * argv[]) {
    try {
        if (argc != 2) {
            throw std::invalid_argument("Missing config arg");
        }

        std::ifstream filestream(argv[1]);
        if (!filestream.is_open()) {
            throw std::runtime_error("Can't open config file");
        }

        json config;
        filestream >> config;

        ServerMonitor mon(config);
        mon.run();

        return EXIT_SUCCESS;
    } catch (const std::exception& ex) {
        std::cout << "ERROR: " << ex.what() << std::endl;
        return EXIT_FAILURE;
    }
}
<|endoftext|>


<commit_before>#include <array>
#include "shared.hpp"

using namespace shared::cyclic;

struct link {
	typedef link const& children_type;
	ptr<link> value;

	struct end_iterator {
		ptr<link> operator*() const {
			return ptr<link>();
		}
		end_iterator next() const {
			return end_iterator();
		}
	};

	end_iterator end() const {
		return end_iterator();
	}

	struct value_iterator {
		ptr<link> const& value_;
		value_iterator(ptr<link> const& value): value_(value) {}
		ptr<link> const& operator*() const {
			return value_;
		}
		end_iterator next() const {
			return end_iterator();
		}
	};

	value_iterator begin() const {
		return value_iterator(value);
	}
};

bool operator!=(link::end_iterator const&, link::end_iterator const&) {
	return false;
}

bool operator!=(link::value_iterator const&, link::end_iterator const&) {
	return true;
}

int main() {
	ptr<link> x = make<link>();
	x->value = x;
	return 0;
}
<commit_msg>generalized for_each<commit_after>#include <array>
#include <iostream>
#include <tuple>
#include <vector>

#include "memory/traceable.hpp"

namespace memory {
	namespace traceable {
		namespace extension {
			template <typename T>
			struct tag_of<std::vector<T>> {
				typedef container_tag type;
			};
		}
	}
}

int main() {
	using namespace memory::traceable;

	std::vector<int> xs { 1, 2, 3 };
	for_each(xs, [](int x) {
			std::cout << x << std::endl;
		});
	std::tuple<int, int, int> ys { 1, 2, 3 };
	for_each(ys, [](int y) {
			std::cout << y << std::endl;
		});
	return 0;
}
<|endoftext|>