<commit_before>#include <iostream>
#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <msgrpc/thrift_struct/thrift_codec.h>
#include <type_traits>
using namespace std;
using namespace std::chrono;

#include "demo/demo_api_declare.h"

#if 0
    #define ___methods_of_interface___IBuzzMath(_, ...)            \
        _(1, ResponseBar, negative_fields, RequestFoo, __VA_ARGS__)\
        _(2, ResponseBar, plus1_to_fields, RequestFoo, __VA_ARGS__)
    ___as_interface(IBuzzMath, __with_interface_id(1))
#endif

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {
    template <typename T> struct Ret {};

    typedef unsigned short msg_id_t;
    typedef unsigned short service_id_t; //TODO: how to deal with different service id types

    struct MsgChannel {
        virtual uint32_t send_msg(const service_id_t& remote_service_id, msg_id_t msg_id, const char* buf, size_t len) const = 0;
    };

    struct Config {
        void initWith(MsgChannel* msg_channel, msgrpc::msg_id_t request_msg_id, msgrpc::msg_id_t response_msg_id) {
            instance().msg_channel_ = msg_channel;
            request_msg_id_  = request_msg_id;
            response_msg_id_ = response_msg_id;
        }

        static inline Config& instance() {
            static thread_local Config instance;
            return instance;
        }

        MsgChannel* msg_channel_;
        msg_id_t request_msg_id_;
        msg_id_t response_msg_id_;
    };
}

namespace msgrpc {

    typedef uint8_t  method_index_t;
    typedef uint16_t iface_index_t;

    struct MsgHeader {
        uint8_t         msgrpc_version_ = {0};
        method_index_t  method_index_in_interface_ = {0};
        iface_index_t   iface_index_in_service_ = {0};

        //TODO: unsigned char  feature_id_in_service_ = {0};
        //TODO: TLV encoded varient length options
        //unsigned long  sequence_no_;
        //optional 1
        /*TODO: call sequence number*/
    };

    /*TODO: consider make msgHeader encoded through thrift*/
    struct ReqMsgHeader : MsgHeader {
    };

    const unsigned short k_rpc_result_succeeded = 0;
    const unsigned short k_rpc_result_failed = 1;
    const unsigned short k_rpc_result_method_not_found = 2;
    const unsigned short k_rpc_result_iface_not_found = 3;

    struct RspMsgHeader : MsgHeader {
        unsigned short rpc_result_ = {k_rpc_result_succeeded};
    };
}

////////////////////////////////////////////////////////////////////////////////
#include "test_util/UdpChannel.h"
namespace demo {
    const msgrpc::msg_id_t k_msgrpc_request_msg_id = 101;
    const msgrpc::msg_id_t k_msgrpc_response_msg_id = 102;

    struct UdpMsgChannel : msgrpc::MsgChannel {
        virtual uint32_t send_msg(const msgrpc::service_id_t& remote_service_id, msgrpc::msg_id_t msg_id, const char* buf, size_t len) const {
            size_t msg_len_with_msgid = sizeof(msgrpc::msg_id_t) + len;
            char* mem = (char*)malloc(msg_len_with_msgid);
            if (mem) {
                *(msgrpc::msg_id_t*)(mem) = msg_id;
                memcpy(mem + sizeof(msgrpc::msg_id_t), buf, len);
                cout << "send msg len: " << msg_len_with_msgid << endl;
                g_msg_channel->send_msg_to_remote(string(mem, msg_len_with_msgid), udp::endpoint(udp::v4(), remote_service_id));
                free(mem);
            } else {
                cout << "send msg failed: allocation failure." << endl;
            }
            return 0;
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
using namespace demo;

const msgrpc::service_id_t k_remote_service_id = 2222;
const msgrpc::service_id_t k_local_service_id  = 3333;

struct IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&) = 0;
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&) = 0;
};

////////////////////////////////////////////////////////////////////////////////
struct IBuzzMathStub : IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&);
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&);
};

msgrpc::Ret<ResponseBar> IBuzzMathStub::negative_fields(const RequestFoo& req) {
    uint8_t* pbuf; uint32_t len;
    /*TODO: extract interface for encode/decode for other protocol adoption such as protobuf*/
    if (!ThriftEncoder::encode(req, &pbuf, &len)) {
        /*TODO: how to do with log, maybe should extract logging interface*/
        cout << "encode failed." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    //TODO: find k_remote_service_id by interface name "IBuzzMath"
    size_t msg_len_with_header = sizeof(msgrpc::ReqMsgHeader) + len;

    char* mem = (char*)malloc(msg_len_with_header);
    if (!mem) {
        cout << "alloc mem failed, during sending rpc request." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    auto header = (msgrpc::ReqMsgHeader*)mem;
    header->msgrpc_version_ = 0;
    header->iface_index_in_service_ = 1;
    header->method_index_in_interface_ = 1;
    memcpy(header + 1, (const char*)pbuf, len);

    cout << "stub sending msg with length: " << msg_len_with_header << endl;
    msgrpc::Config::instance().msg_channel_->send_msg(k_remote_service_id, k_msgrpc_request_msg_id, mem, msg_len_with_header);
    free(mem);
    return msgrpc::Ret<ResponseBar>();
}

msgrpc::Ret<ResponseBar> IBuzzMathStub::plus1_to_fields(const RequestFoo& req) {
    return msgrpc::Ret<ResponseBar>();
}

void local_service() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_local_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {
                IBuzzMathStub buzzMath;
                RequestFoo foo; foo.fooa = 97; foo.__set_foob(98);
                buzzMath.negative_fields(foo);
            } else {
                cout << "local received msg: " << string(msg, len) << endl;
                channel.close();
            }
        }
    );
}

////////////////////////////////////////////////////////////////////////////////

#include <msgrpc/util/singleton.h>

namespace msgrpc {

    struct IfaceImplBase {
        virtual bool onRpcInvoke(const msgrpc::ReqMsgHeader& msg_header, const char* msg, size_t len, msgrpc::RspMsgHeader& rsp_header, uint8_t*& pout_buf, uint32_t& out_buf_len) = 0;
    };

    struct IfaceRepository : msgrpc::Singleton<IfaceRepository> {
        void add_iface_impl(iface_index_t ii, IfaceImplBase* iface) {
            assert(iface != nullptr && "interface implementation can not be null");
            assert(___m.find(ii) == ___m.end() && "interface can only register once");
            ___m[ii] = iface;
        }

        IfaceImplBase* get_iface_impl_by(iface_index_t ii) {
            auto iter = ___m.find(ii);
            return iter == ___m.end() ? nullptr : iter->second;
        }

      private:
        std::map<iface_index_t, IfaceImplBase*> ___m;
    };

    template<typename T, iface_index_t iface_index>
    struct InterfaceImplBaseT : IfaceImplBase {
        InterfaceImplBaseT() {
            IfaceRepository::instance().add_iface_impl(iface_index, this);
        }

        template<typename REQ, typename RSP>
        bool invoke_templated_method( bool (T::*method_impl)(const REQ&, RSP&)
                                    , const char *msg, size_t len
                                    , uint8_t *&pout_buf, uint32_t &out_buf_len) {
            REQ req;
            if (! ThriftDecoder::decode(req, (uint8_t *) msg, len)) {
                cout << "decode failed on remote side." << endl;
                return false;
            }

            RSP rsp;
            if (! ((T*)this->*method_impl)(req, rsp)) {
                //TODO: log
                return false;
            }

            if (! ThriftEncoder::encode(rsp, &pout_buf, &out_buf_len)) {
                cout << "encode failed on remtoe side." << endl;
                return false;
            }

            return true;
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {
    struct RpcReqMsgHandler {
        static void on_rpc_req_msg(msgrpc::msg_id_t msg_id, const char *msg, size_t len) {
            cout << "remote received msg with length: " << len << endl;
            assert(msg_id == k_msgrpc_request_msg_id && "invalid msg id for rpc");

            if (len < sizeof(msgrpc::ReqMsgHeader)) {
                cout << "invalid msg: without sufficient msg header info." << endl;
                return;
            }

            auto *req_header = (msgrpc::ReqMsgHeader *) msg;
            msg += sizeof(msgrpc::ReqMsgHeader);

            msgrpc::RspMsgHeader rsp_header;
            rsp_header.msgrpc_version_ = req_header->msgrpc_version_;
            rsp_header.iface_index_in_service_ = req_header->iface_index_in_service_;
            rsp_header.method_index_in_interface_ = req_header->method_index_in_interface_;

            uint8_t *pout_buf;
            uint32_t out_buf_len;

            IfaceImplBase *iface = IfaceRepository::instance().get_iface_impl_by(req_header->iface_index_in_service_);
            if (iface == nullptr) {
                rsp_header.rpc_result_ = k_rpc_result_iface_not_found;
                msgrpc::Config::instance().msg_channel_->send_msg(k_local_service_id, k_msgrpc_response_msg_id, (const char *) &rsp_header, sizeof(rsp_header));
                return;
            }

            bool ret = iface->onRpcInvoke(*req_header, msg, len - sizeof(msgrpc::ReqMsgHeader), rsp_header, pout_buf, out_buf_len);
            if (ret) {
                return send_msg_with_header(rsp_header, pout_buf, out_buf_len);
            } else {
                msgrpc::Config::instance().msg_channel_->send_msg(k_local_service_id, k_msgrpc_response_msg_id, (const char *) &rsp_header, sizeof(rsp_header));
            }

            //TODO: using pipelined processor to handling input/output msgheader and rpc statistics.
        }

        static void send_msg_with_header(RspMsgHeader &rsp_header, const uint8_t *pout_buf, uint32_t out_buf_len) {
            size_t rsp_len_with_header = sizeof(rsp_header) + out_buf_len;
            char *mem = (char *) malloc(rsp_len_with_header);
            if (mem != nullptr) {
                memcpy(mem, &rsp_header, sizeof(rsp_header));
                memcpy(mem + sizeof(rsp_header), pout_buf, out_buf_len);
                /*TODO: replace k_local_service_id to sender id*/
                Config::instance().msg_channel_->send_msg(k_local_service_id, k_msgrpc_response_msg_id, mem, rsp_len_with_header);
                free(mem);
            }
        }
    };
}
////////////////////////////////////////////////////////////////////////////////

struct IBuzzMathImpl : msgrpc::InterfaceImplBaseT<IBuzzMathImpl, 1> {
    //TODO: try to unify with stub's signature
    bool negative_fields(const RequestFoo& req, ResponseBar& rsp);
    bool plus1_to_fields(const RequestFoo& req, ResponseBar& rsp);

    virtual bool onRpcInvoke(const msgrpc::ReqMsgHeader& msg_header, const char* msg, size_t len, msgrpc::RspMsgHeader& rsp_header, uint8_t*& pout_buf, uint32_t& out_buf_len) override;
};

////////////////////////////////////////////////////////////////////////////////
IBuzzMathImpl buzzMath;

bool IBuzzMathImpl::onRpcInvoke(const msgrpc::ReqMsgHeader& msg_header, const char* msg, size_t len, msgrpc::RspMsgHeader& rsp_header, uint8_t*& pout_buf, uint32_t& out_buf_len) {
    cout << "remote receive rpc invoke with: {" << (int)msg_header.msgrpc_version_ << "|" << (int)msg_header.iface_index_in_service_ << "|" << (int)msg_header.method_index_in_interface_ << "}" << endl;
    bool ret = false;

    if (msg_header.method_index_in_interface_ == 1) {
        ret = this->invoke_templated_method(&IBuzzMathImpl::negative_fields, msg, len, pout_buf, out_buf_len);
    } else

    if (msg_header.method_index_in_interface_ == 2) {
        ret = this->invoke_templated_method(&IBuzzMathImpl::plus1_to_fields, msg, len, pout_buf, out_buf_len);
    } else

    {
        rsp_header.rpc_result_ = msgrpc::k_rpc_result_method_not_found;
        return false;
    }

    if (! ret) {
        rsp_header.rpc_result_ = msgrpc::k_rpc_result_failed;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
bool IBuzzMathImpl::negative_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(req.get_foob());
    if (req.__isset.foob) {
        rsp.__set_barb(req.fooa);
    }
    return true;
}

bool IBuzzMathImpl::plus1_to_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(1 + req.fooa);
    if (req.__isset.foob) {
        rsp.__set_barb(1 + req.get_foob());
    }
    return true;
}

void remote_service() {
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_remote_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {
                return;
            }

            msgrpc::RpcReqMsgHandler::on_rpc_req_msg(msg_id, msg, len);
            channel.close();
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
TEST(async_rpc, should_able_to__auto__register_rpc_interface__after__application_startup) {
    demo::RequestFoo req;
    req.fooa = 1;
    req.__set_foob(2);

    std::thread local_thread(local_service);
    std::thread remote_thread(remote_service);

    local_thread.join();
    remote_thread.join();
};
<commit_msg>refactor<commit_after>#include <iostream>
#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <msgrpc/thrift_struct/thrift_codec.h>
#include <type_traits>
using namespace std;
using namespace std::chrono;

#include "demo/demo_api_declare.h"
////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {
    template <typename T> struct Ret {};

    typedef unsigned short msg_id_t;
    typedef unsigned short service_id_t; //TODO: how to deal with different service id types

    struct MsgChannel {
        virtual uint32_t send_msg(const service_id_t& remote_service_id, msg_id_t msg_id, const char* buf, size_t len) const = 0;
    };

    struct Config {
        void initWith(MsgChannel* msg_channel, msgrpc::msg_id_t request_msg_id, msgrpc::msg_id_t response_msg_id) {
            instance().msg_channel_ = msg_channel;
            request_msg_id_  = request_msg_id;
            response_msg_id_ = response_msg_id;
        }

        static inline Config& instance() {
            static thread_local Config instance;
            return instance;
        }

        MsgChannel* msg_channel_;
        msg_id_t request_msg_id_;
        msg_id_t response_msg_id_;
    };
}

namespace msgrpc {

    typedef uint8_t  method_index_t;
    typedef uint16_t iface_index_t;

    struct MsgHeader {
        uint8_t         msgrpc_version_ = {0};
        method_index_t  method_index_in_interface_ = {0};
        iface_index_t   iface_index_in_service_ = {0};

        //TODO: unsigned char  feature_id_in_service_ = {0};
        //TODO: TLV encoded varient length options
        //unsigned long  sequence_no_;
        //optional 1
        /*TODO: call sequence number*/
    };

    /*TODO: consider make msgHeader encoded through thrift*/
    struct ReqMsgHeader : MsgHeader {
    };

    enum class RpcResult : unsigned short {
        succeeded = 0
        , failed  = 1
        , method_not_found = 2
        , iface_not_found =  3
    };

    struct RspMsgHeader : MsgHeader {
        RpcResult rpc_result_ = { RpcResult::succeeded };
    };
}

////////////////////////////////////////////////////////////////////////////////
#include "test_util/UdpChannel.h"
namespace demo {
    const msgrpc::msg_id_t k_msgrpc_request_msg_id = 101;
    const msgrpc::msg_id_t k_msgrpc_response_msg_id = 102;

    struct UdpMsgChannel : msgrpc::MsgChannel {
        virtual uint32_t send_msg(const msgrpc::service_id_t& remote_service_id, msgrpc::msg_id_t msg_id, const char* buf, size_t len) const {
            size_t msg_len_with_msgid = sizeof(msgrpc::msg_id_t) + len;
            char* mem = (char*)malloc(msg_len_with_msgid);
            if (mem) {
                *(msgrpc::msg_id_t*)(mem) = msg_id;
                memcpy(mem + sizeof(msgrpc::msg_id_t), buf, len);
                cout << "send msg len: " << msg_len_with_msgid << endl;
                g_msg_channel->send_msg_to_remote(string(mem, msg_len_with_msgid), udp::endpoint(udp::v4(), remote_service_id));
                free(mem);
            } else {
                cout << "send msg failed: allocation failure." << endl;
            }
            return 0;
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
using namespace demo;

const msgrpc::service_id_t k_remote_service_id = 2222;
const msgrpc::service_id_t k_local_service_id  = 3333;

struct IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&) = 0;
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&) = 0;
};

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {

    struct IfaceImplBase {
        virtual bool onRpcInvoke(const msgrpc::ReqMsgHeader& msg_header, const char* msg, size_t len, msgrpc::RspMsgHeader& rsp_header, uint8_t*& pout_buf, uint32_t& out_buf_len) = 0;
    };

    struct IfaceRepository : msgrpc::Singleton<IfaceRepository> {
        void add_iface_impl(iface_index_t ii, IfaceImplBase* iface) {
            assert(iface != nullptr && "interface implementation can not be null");
            assert(___m.find(ii) == ___m.end() && "interface can only register once");
            ___m[ii] = iface;
        }

        IfaceImplBase* get_iface_impl_by(iface_index_t ii) {
            auto iter = ___m.find(ii);
            return iter == ___m.end() ? nullptr : iter->second;
        }

      private:
        std::map<iface_index_t, IfaceImplBase*> ___m;
    };

    template<typename T, iface_index_t iface_index>
    struct InterfaceImplBaseT : IfaceImplBase {
        InterfaceImplBaseT() {
            IfaceRepository::instance().add_iface_impl(iface_index, this);
        }

        template<typename REQ, typename RSP>
        bool invoke_templated_method( bool (T::*method_impl)(const REQ&, RSP&)
                                    , const char *msg, size_t len
                                    , uint8_t *&pout_buf, uint32_t &out_buf_len) {
            REQ req;
            if (! ThriftDecoder::decode(req, (uint8_t *) msg, len)) {
                cout << "decode failed on remote side." << endl;
                return false;
            }

            RSP rsp;
            if (! ((T*)this->*method_impl)(req, rsp)) {
                //TODO: log
                return false;
            }

            if (! ThriftEncoder::encode(rsp, &pout_buf, &out_buf_len)) {
                cout << "encode failed on remtoe side." << endl;
                return false;
            }

            return true;
        }
    };
}

////////////////////////////////////////////////////////////////////////////////
namespace msgrpc {
    struct RpcReqMsgHandler {
        static void on_rpc_req_msg(msgrpc::msg_id_t msg_id, const char *msg, size_t len) {
            cout << "remote received msg with length: " << len << endl;
            assert(msg_id == k_msgrpc_request_msg_id && "invalid msg id for rpc");

            if (len < sizeof(msgrpc::ReqMsgHeader)) {
                cout << "invalid msg: without sufficient msg header info." << endl;
                return;
            }

            auto *req_header = (msgrpc::ReqMsgHeader *) msg;
            msg += sizeof(msgrpc::ReqMsgHeader);

            msgrpc::RspMsgHeader rsp_header;
            rsp_header.msgrpc_version_ = req_header->msgrpc_version_;
            rsp_header.iface_index_in_service_ = req_header->iface_index_in_service_;
            rsp_header.method_index_in_interface_ = req_header->method_index_in_interface_;

            uint8_t *pout_buf;
            uint32_t out_buf_len;

            IfaceImplBase *iface = IfaceRepository::instance().get_iface_impl_by(req_header->iface_index_in_service_);
            if (iface == nullptr) {
                rsp_header.rpc_result_ = RpcResult::iface_not_found;
                msgrpc::Config::instance().msg_channel_->send_msg(k_local_service_id, k_msgrpc_response_msg_id, (const char *) &rsp_header, sizeof(rsp_header));
                return;
            }

            bool ret = iface->onRpcInvoke(*req_header, msg, len - sizeof(msgrpc::ReqMsgHeader), rsp_header, pout_buf, out_buf_len);
            if (ret) {
                return send_msg_with_header(rsp_header, pout_buf, out_buf_len);
            } else {
                msgrpc::Config::instance().msg_channel_->send_msg(k_local_service_id, k_msgrpc_response_msg_id, (const char *) &rsp_header, sizeof(rsp_header));
            }

            //TODO: using pipelined processor to handling input/output msgheader and rpc statistics.
        }

        static void send_msg_with_header(RspMsgHeader &rsp_header, const uint8_t *pout_buf, uint32_t out_buf_len) {
            size_t rsp_len_with_header = sizeof(rsp_header) + out_buf_len;
            char *mem = (char *) malloc(rsp_len_with_header);
            if (mem != nullptr) {
                memcpy(mem, &rsp_header, sizeof(rsp_header));
                memcpy(mem + sizeof(rsp_header), pout_buf, out_buf_len);
                /*TODO: replace k_local_service_id to sender id*/
                Config::instance().msg_channel_->send_msg(k_local_service_id, k_msgrpc_response_msg_id, mem, rsp_len_with_header);
                free(mem);
            }
        }
    };
}
////////////////////////////////////////////////////////////////////////////////
struct IBuzzMathImpl : msgrpc::InterfaceImplBaseT<IBuzzMathImpl, 1> {
    bool negative_fields(const RequestFoo& req, ResponseBar& rsp);
    bool plus1_to_fields(const RequestFoo& req, ResponseBar& rsp);

    virtual bool onRpcInvoke(const msgrpc::ReqMsgHeader& req_header, const char* msg, size_t len, msgrpc::RspMsgHeader& rsp_header, uint8_t*& pout_buf, uint32_t& out_buf_len) override;
};

////////////////////////////////////////////////////////////////////////////////
IBuzzMathImpl buzzMath;

bool IBuzzMathImpl::onRpcInvoke(const msgrpc::ReqMsgHeader& req_header, const char* msg, size_t len, msgrpc::RspMsgHeader& rsp_header, uint8_t*& pout_buf, uint32_t& out_buf_len) {
    bool ret = false;

    if (req_header.method_index_in_interface_ == 1) {
        ret = this->invoke_templated_method(&IBuzzMathImpl::negative_fields, msg, len, pout_buf, out_buf_len);
    } else

    if (req_header.method_index_in_interface_ == 2) {
        ret = this->invoke_templated_method(&IBuzzMathImpl::plus1_to_fields, msg, len, pout_buf, out_buf_len);
    } else

    {
        rsp_header.rpc_result_ = msgrpc::RpcResult::method_not_found;
        return false;
    }

    if (! ret) {
        rsp_header.rpc_result_ = msgrpc::RpcResult::failed;
    }

    return ret;
}

////////////////////////////////////////////////////////////////////////////////
bool IBuzzMathImpl::negative_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(req.get_foob());
    if (req.__isset.foob) {
        rsp.__set_barb(req.fooa);
    }
    return true;
}

bool IBuzzMathImpl::plus1_to_fields(const RequestFoo& req, ResponseBar& rsp) {
    rsp.__set_bara(1 + req.fooa);
    if (req.__isset.foob) {
        rsp.__set_barb(1 + req.get_foob());
    }
    return true;
}

////////////////////////////////////////////////////////////////////////////////
void remote_service() {
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_remote_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {
                return;
            }

            msgrpc::RpcReqMsgHandler::on_rpc_req_msg(msg_id, msg, len);
            channel.close();
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
#if 0
    #define ___methods_of_interface___IBuzzMath(_, ...)            \
        _(1, ResponseBar, negative_fields, RequestFoo, __VA_ARGS__)\
        _(2, ResponseBar, plus1_to_fields, RequestFoo, __VA_ARGS__)
    ___as_interface(IBuzzMath, __with_interface_id(1))
#endif

////////////////////////////////////////////////////////////////////////////////
struct IBuzzMathStub : IBuzzMath {
    virtual msgrpc::Ret<ResponseBar> negative_fields(const RequestFoo&);
    virtual msgrpc::Ret<ResponseBar> plus1_to_fields(const RequestFoo&);
};

msgrpc::Ret<ResponseBar> IBuzzMathStub::negative_fields(const RequestFoo& req) {
    uint8_t* pbuf; uint32_t len;
    /*TODO: extract interface for encode/decode for other protocol adoption such as protobuf*/
    if (!ThriftEncoder::encode(req, &pbuf, &len)) {
        /*TODO: how to do with log, maybe should extract logging interface*/
        cout << "encode failed." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    //TODO: find k_remote_service_id by interface name "IBuzzMath"
    size_t msg_len_with_header = sizeof(msgrpc::ReqMsgHeader) + len;

    char* mem = (char*)malloc(msg_len_with_header);
    if (!mem) {
        cout << "alloc mem failed, during sending rpc request." << endl;
        return msgrpc::Ret<ResponseBar>();
    }

    auto header = (msgrpc::ReqMsgHeader*)mem;
    header->msgrpc_version_ = 0;
    header->iface_index_in_service_ = 1;
    header->method_index_in_interface_ = 1;
    memcpy(header + 1, (const char*)pbuf, len);

    cout << "stub sending msg with length: " << msg_len_with_header << endl;
    msgrpc::Config::instance().msg_channel_->send_msg(k_remote_service_id, k_msgrpc_request_msg_id, mem, msg_len_with_header);
    free(mem);
    return msgrpc::Ret<ResponseBar>();
}

msgrpc::Ret<ResponseBar> IBuzzMathStub::plus1_to_fields(const RequestFoo& req) {
    return msgrpc::Ret<ResponseBar>();
}

void local_service() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    msgrpc::Config::instance().initWith(new UdpMsgChannel(), k_msgrpc_request_msg_id, k_msgrpc_response_msg_id);

    UdpChannel channel(k_local_service_id,
        [&channel](msgrpc::msg_id_t msg_id, const char* msg, size_t len) {
            if (0 == strcmp(msg, "init")) {
                IBuzzMathStub buzzMath;
                RequestFoo foo; foo.fooa = 97; foo.__set_foob(98);
                buzzMath.negative_fields(foo);
            } else {
                cout << "local received msg: " << string(msg, len) << endl;
                channel.close();
            }
        }
    );
}

////////////////////////////////////////////////////////////////////////////////
TEST(async_rpc, should_able_to__auto__register_rpc_interface__after__application_startup) {
    demo::RequestFoo req;
    req.fooa = 1;
    req.__set_foob(2);

    std::thread local_thread(local_service);
    std::thread remote_thread(remote_service);

    local_thread.join();
    remote_thread.join();
};
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity compiler.
 */

#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>

using namespace std;
using namespace dev::eth;

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{

bytes compileContract(const string& _sourceCode)
{
	Parser parser;
	ASTPointer<SourceUnit> sourceUnit;
	BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
	NameAndTypeResolver resolver({});
	resolver.registerDeclarations(*sourceUnit);
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));

			Compiler compiler;
			compiler.compileContract(*contract, {});
			// debug
			//compiler.streamAssembly(cout);
			return compiler.getAssembledBytecode();
		}
	BOOST_FAIL("No contract found in source.");
	return bytes();
}

/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
/// This is necessary since the compiler will add boilerplate add the beginning that is not
/// tested here.
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset)
{
	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size());
	auto checkStart = _compiledCode.begin() + _offset;
	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(),
								  _expectation.begin(), _expectation.end());
}

} // end anonymous namespace

BOOST_AUTO_TEST_SUITE(SolidityCompiler)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { var x = 2; }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 40;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::SWAP1),
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(different_argument_numbers)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a, uint b, uint c) returns(uint d) { return b; }\n"
							 "  function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 68;
	unsigned boilerplateSize = 81;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize return variable d
					   byte(Instruction::DUP3),
					   byte(Instruction::SWAP1), // assign b to d
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0xa + shift), // jump to return
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP4), // store d and fetch return address
					   byte(Instruction::SWAP3), // store return address
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP), // end of f
					   byte(Instruction::JUMPDEST), // beginning of g
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::PUSH1), 0x0, // initialized e and h
					   byte(Instruction::PUSH1), byte(0x2a + shift), // ret address
					   byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
					   byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
					   byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
					   byte(Instruction::PUSH1), byte(0x1 + shift),
					   // stack here: ret e h 0x20 1 2 3 0x1
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   // stack here: ret e h f(1,2,3)
					   byte(Instruction::SWAP1),
					   // stack here: ret e f(1,2,3) h
					   byte(Instruction::POP),
					   byte(Instruction::DUP1), // retrieve it again as "value of expression"
					   byte(Instruction::POP), // end of assignment
					   // stack here: ret e f(1,2,3)
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP1),
					   // ret e f(1,2,3)
					   byte(Instruction::SWAP2),
					   // f(1,2,3) e ret
					   byte(Instruction::JUMP) // end of g
					   });
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(ifStatement)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 27;
	unsigned boilerplateSize = 40;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1),
					   byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target
					   byte(Instruction::JUMPI),
					   // new check "else if" condition
					   byte(Instruction::DUP1),
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x13 + shift),
					   byte(Instruction::JUMPI),
					   // "else" body
					   byte(Instruction::PUSH1), 0x4f,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part
					   byte(Instruction::JUMP),
					   // "else if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4e,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), byte(0x1f + shift),
					   byte(Instruction::JUMP),
					   // "if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4d,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(loops)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { while(true){1;break;2;continue;3;return;4;} }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 27;
	unsigned boilerplateSize = 40;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMPI),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMP), // break
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP), // continue
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x22 + shift),
					   byte(Instruction::JUMP), // return
					   byte(Instruction::PUSH1), 0x4,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMP)});

	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<commit_msg>Create contracts.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity compiler.
 */

#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>

using namespace std;
using namespace dev::eth;

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{

bytes compileContract(const string& _sourceCode)
{
	Parser parser;
	ASTPointer<SourceUnit> sourceUnit;
	BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
	NameAndTypeResolver resolver({});
	resolver.registerDeclarations(*sourceUnit);
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));

			Compiler compiler;
			compiler.compileContract(*contract, {}, {});
			// debug
			//compiler.streamAssembly(cout);
			return compiler.getAssembledBytecode();
		}
	BOOST_FAIL("No contract found in source.");
	return bytes();
}

/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
/// This is necessary since the compiler will add boilerplate add the beginning that is not
/// tested here.
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset)
{
	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size());
	auto checkStart = _compiledCode.begin() + _offset;
	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(),
								  _expectation.begin(), _expectation.end());
}

} // end anonymous namespace

BOOST_AUTO_TEST_SUITE(SolidityCompiler)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { var x = 2; }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 40;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::SWAP1),
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(different_argument_numbers)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a, uint b, uint c) returns(uint d) { return b; }\n"
							 "  function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 68;
	unsigned boilerplateSize = 81;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize return variable d
					   byte(Instruction::DUP3),
					   byte(Instruction::SWAP1), // assign b to d
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0xa + shift), // jump to return
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP4), // store d and fetch return address
					   byte(Instruction::SWAP3), // store return address
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP), // end of f
					   byte(Instruction::JUMPDEST), // beginning of g
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::PUSH1), 0x0, // initialized e and h
					   byte(Instruction::PUSH1), byte(0x2a + shift), // ret address
					   byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
					   byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
					   byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
					   byte(Instruction::PUSH1), byte(0x1 + shift),
					   // stack here: ret e h 0x20 1 2 3 0x1
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   // stack here: ret e h f(1,2,3)
					   byte(Instruction::SWAP1),
					   // stack here: ret e f(1,2,3) h
					   byte(Instruction::POP),
					   byte(Instruction::DUP1), // retrieve it again as "value of expression"
					   byte(Instruction::POP), // end of assignment
					   // stack here: ret e f(1,2,3)
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP1),
					   // ret e f(1,2,3)
					   byte(Instruction::SWAP2),
					   // f(1,2,3) e ret
					   byte(Instruction::JUMP) // end of g
					   });
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(ifStatement)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 27;
	unsigned boilerplateSize = 40;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1),
					   byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target
					   byte(Instruction::JUMPI),
					   // new check "else if" condition
					   byte(Instruction::DUP1),
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x13 + shift),
					   byte(Instruction::JUMPI),
					   // "else" body
					   byte(Instruction::PUSH1), 0x4f,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part
					   byte(Instruction::JUMP),
					   // "else if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4e,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), byte(0x1f + shift),
					   byte(Instruction::JUMP),
					   // "if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4d,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(loops)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { while(true){1;break;2;continue;3;return;4;} }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 27;
	unsigned boilerplateSize = 40;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMPI),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMP), // break
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP), // continue
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x22 + shift),
					   byte(Instruction::JUMP), // return
					   byte(Instruction::PUSH1), 0x4,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMP)});

	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<|endoftext|>


<commit_before><commit_msg>Avoided warnings on VC++ Pro.<commit_after><|endoftext|>


<commit_before>// Validator.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <vector>
#include <unordered_set>
#include <string>
#include <fstream>
#include <functional>
#include "Option.h"
#include "Scorer.h"
#include "../common/Graph.h"
#include "../common/Motif.h"
#include "../common/SubjectInfo.h"
#include <boost/filesystem.hpp>

using namespace std;

Graph loadGraph(istream& is) {
	Graph res;
	res.readFromStream(is);
	return res;
}

vector<vector<Graph> > loadData(const string& pre, const int n, const int m) {
	vector<vector<Graph> > res;
	res.reserve(n);
	for(int i = 0; i < n; ++i) {
		vector<Graph> temp;
		temp.reserve(m);
		for(int j = 0; j < m; ++j) {
			ifstream fin(pre + to_string(i) + "-" + to_string(j) + ".txt");
			temp.push_back(loadGraph(fin));
		}
		res.push_back(move(temp));
	}
	return res;
}

vector<vector<Graph> > loadData(
	const string& folder, const vector<int>& types, const int nSub, const int nSnap, const int nSkip = 0)
{
	boost::filesystem::path root(folder);
	if(!exists(root)) {
		cerr << "cannot open graph folder: " << folder << endl;
		throw invalid_argument("cannot open graph folder: " + folder);
	}
	size_t limitSub = nSub >= 0 ? nSub : numeric_limits<size_t>::max();
	size_t limitSnp = nSnap > 0 ? nSnap : numeric_limits<size_t>::max();
	unordered_set<int> validType(types.begin(), types.end());

	// sort up the file list (ensure the file order)
	map<decltype(SubjectInfo::id), vector<string>> id2fn;
	for(auto it = boost::filesystem::directory_iterator(root);
		it != boost::filesystem::directory_iterator(); ++it)
	{
		SubjectInfo sub;
		string fn = it->path().filename().string();
		if(boost::filesystem::is_regular_file(it->status()) && sub.parseFromFilename(fn)) {
			// check type
			if(validType.find(sub.type) == validType.end())
				continue;
			id2fn[sub.id].push_back(move(fn));
		}
	}
	// load data
	vector<vector<Graph> > res(min(limitSub, id2fn.size()));
	int cntSub = 0;
	size_t pres = 0;
	for(auto& sfp : id2fn) {
		if(++cntSub <= nSkip)
			continue;
		else if(pres >= limitSub)
			break;
		//		cout <<"rank: "<<rank<< " type: " << types[0] << " id: " << sfp.first << endl;
		// sort the snapshot files
		if(sfp.second.size() <= limitSnp) {
			sort(sfp.second.begin(), sfp.second.end());
		} else {
			auto it = sfp.second.begin() + limitSnp;
			partial_sort(sfp.second.begin(), it, sfp.second.end());
		}
		vector<Graph>& vec = res[pres++];
		size_t cntSnp = 0;
		for(auto& fn : sfp.second) {
			if(++cntSnp > limitSnp)
				break;
			ifstream fin(folder + fn);
			if(!fin) {
				cerr << "cannot open file: " << fn << endl;
			}
			vec.push_back(loadGraph(fin));
		}
	}
	return res;
}

Motif parseMotif(const std::string& line) {
	size_t plast = line.find('\t') + 1;
	size_t p = line.find('\t', plast);
	int nEdge = stoi(line.substr(plast, p - plast));
	plast = p + 2;
	Motif m;
	while(nEdge--) {
		size_t pmid = line.find(',', plast);
		int s = stoi(line.substr(plast, pmid - plast));
		pmid++;
		p = line.find(')', pmid);
		int d = stoi(line.substr(pmid, p - pmid));
		m.addEdge(s, d);
		plast = p + 3;
	}
	return m;
}

bool existOnSub(const std::vector<Graph>& gs, const Motif& m, const double theta)
{
	int cnt = 0;
	int limit = static_cast<int>(ceil(gs.size()*theta));
	for(auto& g : gs) {
		if(g.testMotif(m)) {
			if(++cnt >= limit)
				return true;
		}
	}
	return false;
}

double probOnGS(const vector<vector<Graph>>& gs, const Motif& m, const double theta)
{
	int cnt = 0;
	for(auto& l : gs)
		if(existOnSub(l, m, theta))
			++cnt;
	return static_cast<double>(cnt) / gs.size();
}

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& param) {
	for(auto& p : param)
		os << p << " ";
	return os;
}

int main(int argc, char* argv[])
{
	Option opt;
	if(!opt.parseInput(argc, argv)) {
		return 1;
	}

	function<double(const double, const double)> objFun;
	if(opt.funName == "diff") {
		objFun = bind(&Scorer::diff, placeholders::_1, placeholders::_2, opt.alpha);
	} else if(opt.funName == "ratio") {
		objFun = Scorer::ratio;
	}

	int nPosSub = opt.nPosInd, nPosSkip = 0;
	int nNegSub = opt.nNegInd, nNegSkip = 0;
	cout << "Loading graphs on rank..." << endl;
	vector<vector<Graph> > gPos = loadData(opt.graphFolder, opt.typePos, nPosSub, opt.nSnapshot, nPosSkip);
	cout << "  # positive subjects: " << gPos.size() << endl;
	vector<vector<Graph> > gNeg = loadData(opt.graphFolder, opt.typeNeg, nNegSub, opt.nSnapshot, nNegSkip);
	cout << "  # negative subjects: " << gNeg.size() << endl;

	string line;
	cout << "Waiting for input: Format:\n"
		"nNode	nEdge	(a,b) (c,d) (...)"<< endl;
	while(getline(cin, line)) {
		Motif m;
		try {
			m = parseMotif(line);
		} catch(...) {
			cout << "cannot parse given motif." << endl;
			continue;
		}
		double fPos = probOnGS(gPos, m, opt.theta);
		double fNeg = probOnGS(gNeg, m, opt.theta);
		double score = objFun(fPos, fNeg);
		cout << "fPos=" << fPos << ", fNeg=" << fNeg << ", score=" << score << endl;
	}
	return 0;
}

<commit_msg>description fix<commit_after>// Validator.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <vector>
#include <unordered_set>
#include <string>
#include <fstream>
#include <functional>
#include "Option.h"
#include "Scorer.h"
#include "../common/Graph.h"
#include "../common/Motif.h"
#include "../common/SubjectInfo.h"
#include <boost/filesystem.hpp>

using namespace std;

Graph loadGraph(istream& is) {
	Graph res;
	res.readFromStream(is);
	return res;
}

vector<vector<Graph> > loadData(const string& pre, const int n, const int m) {
	vector<vector<Graph> > res;
	res.reserve(n);
	for(int i = 0; i < n; ++i) {
		vector<Graph> temp;
		temp.reserve(m);
		for(int j = 0; j < m; ++j) {
			ifstream fin(pre + to_string(i) + "-" + to_string(j) + ".txt");
			temp.push_back(loadGraph(fin));
		}
		res.push_back(move(temp));
	}
	return res;
}

vector<vector<Graph> > loadData(
	const string& folder, const vector<int>& types, const int nSub, const int nSnap, const int nSkip = 0)
{
	boost::filesystem::path root(folder);
	if(!exists(root)) {
		cerr << "cannot open graph folder: " << folder << endl;
		throw invalid_argument("cannot open graph folder: " + folder);
	}
	size_t limitSub = nSub >= 0 ? nSub : numeric_limits<size_t>::max();
	size_t limitSnp = nSnap > 0 ? nSnap : numeric_limits<size_t>::max();
	unordered_set<int> validType(types.begin(), types.end());

	// sort up the file list (ensure the file order)
	map<decltype(SubjectInfo::id), vector<string>> id2fn;
	for(auto it = boost::filesystem::directory_iterator(root);
		it != boost::filesystem::directory_iterator(); ++it)
	{
		SubjectInfo sub;
		string fn = it->path().filename().string();
		if(boost::filesystem::is_regular_file(it->status()) && sub.parseFromFilename(fn)) {
			// check type
			if(validType.find(sub.type) == validType.end())
				continue;
			id2fn[sub.id].push_back(move(fn));
		}
	}
	// load data
	vector<vector<Graph> > res(min(limitSub, id2fn.size()));
	int cntSub = 0;
	size_t pres = 0;
	for(auto& sfp : id2fn) {
		if(++cntSub <= nSkip)
			continue;
		else if(pres >= limitSub)
			break;
		//		cout <<"rank: "<<rank<< " type: " << types[0] << " id: " << sfp.first << endl;
		// sort the snapshot files
		if(sfp.second.size() <= limitSnp) {
			sort(sfp.second.begin(), sfp.second.end());
		} else {
			auto it = sfp.second.begin() + limitSnp;
			partial_sort(sfp.second.begin(), it, sfp.second.end());
		}
		vector<Graph>& vec = res[pres++];
		size_t cntSnp = 0;
		for(auto& fn : sfp.second) {
			if(++cntSnp > limitSnp)
				break;
			ifstream fin(folder + fn);
			if(!fin) {
				cerr << "cannot open file: " << fn << endl;
			}
			vec.push_back(loadGraph(fin));
		}
	}
	return res;
}

Motif parseMotif(const std::string& line) {
	size_t plast = line.find('\t') + 1;
	size_t p = line.find('\t', plast);
	int nEdge = stoi(line.substr(plast, p - plast));
	plast = p + 2;
	Motif m;
	while(nEdge--) {
		size_t pmid = line.find(',', plast);
		int s = stoi(line.substr(plast, pmid - plast));
		pmid++;
		p = line.find(')', pmid);
		int d = stoi(line.substr(pmid, p - pmid));
		m.addEdge(s, d);
		plast = p + 3;
	}
	return m;
}

bool existOnSub(const std::vector<Graph>& gs, const Motif& m, const double theta)
{
	int cnt = 0;
	int limit = static_cast<int>(ceil(gs.size()*theta));
	for(auto& g : gs) {
		if(g.testMotif(m)) {
			if(++cnt >= limit)
				return true;
		}
	}
	return false;
}

double probOnGS(const vector<vector<Graph>>& gs, const Motif& m, const double theta)
{
	int cnt = 0;
	for(auto& l : gs)
		if(existOnSub(l, m, theta))
			++cnt;
	return static_cast<double>(cnt) / gs.size();
}

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& param) {
	for(auto& p : param)
		os << p << " ";
	return os;
}

int main(int argc, char* argv[])
{
	Option opt;
	if(!opt.parseInput(argc, argv)) {
		return 1;
	}

	function<double(const double, const double)> objFun;
	if(opt.funName == "diff") {
		objFun = bind(&Scorer::diff, placeholders::_1, placeholders::_2, opt.alpha);
	} else if(opt.funName == "ratio") {
		objFun = Scorer::ratio;
	}

	int nPosSub = opt.nPosInd, nPosSkip = 0;
	int nNegSub = opt.nNegInd, nNegSkip = 0;
	cout << "Loading graphs on rank..." << endl;
	vector<vector<Graph> > gPos = loadData(opt.graphFolder, opt.typePos, nPosSub, opt.nSnapshot, nPosSkip);
	cout << "  # positive subjects: " << gPos.size() << endl;
	vector<vector<Graph> > gNeg = loadData(opt.graphFolder, opt.typeNeg, nNegSub, opt.nSnapshot, nNegSkip);
	cout << "  # negative subjects: " << gNeg.size() << endl;

	string line;
	cout << "Format:\n"
		"sth	nEdge	(a,b) (c,d) (...)"
		"Waiting for input (one per line): "<< endl;
	while(getline(cin, line)) {
		Motif m;
		try {
			m = parseMotif(line);
		} catch(...) {
			cout << "cannot parse given motif." << endl;
			continue;
		}
		double fPos = probOnGS(gPos, m, opt.theta);
		double fNeg = probOnGS(gNeg, m, opt.theta);
		double score = objFun(fPos, fNeg);
		cout << "fPos=" << fPos << ", fNeg=" << fNeg << ", score=" << score << endl;
	}
	return 0;
}

<|endoftext|>


<commit_before>/**
 * \file   main.cc
 * \Author Andrea Barberio <insomniac@slackware.it>
 * \date   October 2015
 * \brief  entry point for dublin-traceroute
 *
 * This file contains the main routine for calling the standalone dublin-traceroute
 * executable.
 */

#include <iostream>
#include <fstream>

#include <dublintraceroute/dublin_traceroute.h>

// TODO argument parsing

#define TARGET		"8.8.8.8"
#define PATHS		10

void
usage(const char *name) {
	std::cout << "Usage: " << name << " target" << std::endl;
	exit(EXIT_FAILURE);
}

int
main(int argc, char **argv) {
	if (argc != 2)
		usage(argv[0]);

	const std::string target = std::string(argv[1]);
	std::cout << "Starting dublin-traceroute" << std::endl;

	DublinTraceroute Dublin(
			target,
			12345,
			(1<<15) + 666,  // traceroute's port
			PATHS
	);
	std::cout
		<< "Traceroute from 0.0.0.0:" << Dublin.srcport()
		<< " to " << Dublin.dst()
		<< ":" << Dublin.dstport() << "~" << (Dublin.dstport() + PATHS - 1)
		<< std::endl;

	std::shared_ptr<TracerouteResults> results;
	try {
		results = std::make_shared<TracerouteResults>(Dublin.traceroute());
	} catch (DublinTracerouteException &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	} catch (std::runtime_error &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	}

	results->show();

	// Save as JSON
	std::ofstream jsonfile;
	jsonfile.open("trace.json");
	jsonfile << results->to_json();
	jsonfile.close();
	std::cout << "Saved JSON file to trace.json ." << std::endl;

	std::cout << "You can convert it to DOT by running scripts/to_graphviz.py trace.json" << std::endl;
}

<commit_msg>Update main.cc<commit_after>/**
 * \file   main.cc
 * \Author Andrea Barberio <insomniac@slackware.it>
 * \date   October 2015
 * \brief  entry point for dublin-traceroute
 *
 * This file contains the main routine for calling the standalone dublin-traceroute
 * executable.
 */

#include <iostream>
#include <fstream>

#include <dublintraceroute/dublin_traceroute.h>

// TODO argument parsing

#define TARGET		"8.8.8.8"
#define PATHS		10

void
usage(const char *name) {
	std::cout << "Usage: " << name << " target" << std::endl;
	exit(EXIT_FAILURE);
}

int
main(int argc, char **argv) {
	if (argc != 2)
		usage(argv[0]);

	const std::string target = std::string(argv[1]);
	std::cout << "Starting dublin-traceroute" << std::endl;

	DublinTraceroute Dublin(
			target,
			12345,
			(1<<15) + 666,  // traceroute's port
			PATHS
	);
	std::cout
		<< "Traceroute from 0.0.0.0:" << Dublin.srcport()
		<< " to " << Dublin.dst()
		<< ":" << Dublin.dstport() << "~" << (Dublin.dstport() + PATHS - 1)
		<< std::endl;

	std::shared_ptr<TracerouteResults> results;
	try {
		results = std::make_shared<TracerouteResults>(Dublin.traceroute());
	} catch (DublinTracerouteException &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	} catch (std::runtime_error &e) {
		std::cout << "Failed: " << e.what() << std::endl;
		exit(EXIT_FAILURE);
	}

	results->show();

	// Save as JSON
	std::ofstream jsonfile;
	jsonfile.open("trace.json");
	jsonfile << results->to_json();
	jsonfile.close();
	std::cout << "Saved JSON file to trace.json ." << std::endl;

	std::cout << "You can convert it to DOT by running python -m dublintraceroute --plot trace.json" << std::endl;
}

<|endoftext|>


<commit_before>#include <cstdio>
#include <fstream>
#include <iostream>

#include <boost/program_options/errors.hpp>

#include "conf/fill_configuration.hh"
#include "mc/work.hh"
#include "parsers/parse.hh"
#include "parsers/parse_error.hh"

/*------------------------------------------------------------------------------------------------*/

int
main(int argc, char** argv)
{
  using namespace pnmc;

  try
  {
    const auto conf_opt = conf::fill_configuration(argc, argv);
    if (conf_opt) // configuration succeeded
    {
      const auto& conf = *conf_opt;
      std::istream* in;
      std::ifstream fstream;
      if (conf.read_stdin)
      {
        in = &std::cin;
      }
      else
      {
        fstream = std::ifstream(conf.file_name);
        if (not fstream.is_open())
        {
          std::cerr << "Can't open " << conf.file_name << std::endl;
          return 1;
        }
        in = &fstream;
      }

      // Try to parse the model.
      try
      {
        const auto net_ptr = parsers::parse(conf, *in);
        if (conf.delete_file and not conf.read_stdin)
        {
          std::remove(conf.file_name.c_str());
        }
        mc::work(conf, *net_ptr);
      }
      catch (const parsers::parse_error& p)
      {
        std::cerr << "Error when parsing input." << std::endl;
        std::cerr << p.what() << std::endl;
        return 1;
      }
    }
  }
  catch (const boost::program_options::error& e)
  {
    std::cerr << e.what() << std::endl;
    return 1;
  }
  return 0;
}

/*------------------------------------------------------------------------------------------------*/
<commit_msg>No raw pointers to handle the file or cin dispatch.<commit_after>#include <cstdio>
#include <fstream>
#include <iostream>

#include <boost/program_options/errors.hpp>

#include "conf/fill_configuration.hh"
#include "mc/work.hh"
#include "parsers/parse.hh"
#include "parsers/parse_error.hh"

/*------------------------------------------------------------------------------------------------*/

namespace pnmc {

struct unreadable_file
  : std::exception
{};

std::shared_ptr<std::istream>
file_or_cin(const conf::pnmc_configuration& conf)
{
  if (conf.read_stdin)
  {
    std::ios_base::sync_with_stdio(false); // Standard input buffering.
    return std::shared_ptr<std::istream>(&std::cin, [](std::istream*){}); // Avoid to erase cin.
  }
  else
  {
    std::shared_ptr<std::istream> ptr(new std::ifstream(conf.file_name));
    if (not dynamic_cast<std::ifstream&>(*ptr).is_open())
    {
      throw unreadable_file();
    }
    return ptr;
  }
}

} // namespace pnmc

/*------------------------------------------------------------------------------------------------*/

int
main(int argc, char** argv)
{
  using namespace pnmc;

  try
  {
    const auto conf_opt = conf::fill_configuration(argc, argv);
    if (conf_opt) // configuration succeeded
    {
      const auto& conf = *conf_opt;
      try
      {
        auto in = file_or_cin(conf);
        const auto net_ptr = parsers::parse(conf, *in);
        if (conf.delete_file and not conf.read_stdin)
        {
          std::remove(conf.file_name.c_str());
        }
        mc::work(conf, *net_ptr);
      }
      catch (const unreadable_file&)
      {
        std::cerr << "Can't open '" << conf.file_name << "'." << std::endl;
        return 2;
      }
      catch (const parsers::parse_error& p)
      {
        std::cerr << "Error when parsing input." << std::endl;
        std::cerr << p.what() << std::endl;
        return 3;
      }
    }
  }
  catch (const boost::program_options::error& e)
  {
    std::cerr << e.what() << std::endl;
    return 1;
  }
  return 0;
}

/*------------------------------------------------------------------------------------------------*/
<|endoftext|>


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

QGroundControl Open Source Ground Control Station

(c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Main executable
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QApplication>
#include "QGCCore.h"
#include "MainWindow.h"
#include "configuration.h"
#include "SerialLink.h"
#include "TCPLink.h"
#ifdef QT_DEBUG
#include "AutoTest.h"
#include "CmdLineOptParser.h"
#ifdef Q_OS_WIN
#include <crtdbg.h>
#endif
#endif

/* SDL does ugly things to main() */
#ifdef main
#undef main
#endif

#ifdef Q_OS_WIN

/// @brief Message handler which is installed using qInstallMsgHandler so you do not need
/// the MSFT debug tools installed to see qDebug(), qWarning(), qCritical and qAbort
void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    const char symbols[] = { 'I', 'E', '!', 'X' };
    QString output = QString("[%1] at %2:%3 - \"%4\"").arg(symbols[type]).arg(context.file).arg(context.line).arg(msg);
    std::cerr << output.toStdString() << std::endl;
    if( type == QtFatalMsg ) abort();
}

/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when
/// we don't want asserts to pop a dialog on windows.
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
{
    Q_UNUSED(reportType);

    std::cerr << message << std::endl;  // Output message to stderr
    *returnValue = 0;                   // Don't break into debugger
    return true;                        // We handled this fully ourselves
}

#endif

/**
 * @brief Starts the application
 *
 * @param argc Number of commandline arguments
 * @param argv Commandline arguments
 * @return exit code, 0 for normal exit and !=0 for error cases
 */

int main(int argc, char *argv[])
{

#ifdef Q_OS_MAC
    // Prevent Apple's app nap from screwing us over
    // tip: the domain can be cross-checked on the command line with <defaults domains>
    QProcess::execute("defaults write org.qgroundcontrol.qgroundcontrol NSAppSleepDisabled -bool YES");
#endif

    // install the message handler
#ifdef Q_OS_WIN
    qInstallMessageHandler(msgHandler);
#endif

    // The following calls to qRegisterMetaType are done to silence debug output which warns
    // that we use these types in signals, and without calling qRegisterMetaType we can't queue
    // these signals. In general we don't queue these signals, but we do what the warning says
    // anyway to silence the debug output.
    qRegisterMetaType<QSerialPort::SerialPortError>();
    qRegisterMetaType<QAbstractSocket::SocketError>();

#ifdef QT_DEBUG
    // We parse a small set of command line options here prior to QGCCore in order to handle the ones
    // which need to be handled before a QApplication object is started.

    bool runUnitTests = false;          // Run unit test
    bool quietWindowsAsserts = false;   // Don't let asserts pop dialog boxes

    CmdLineOpt_t rgCmdLineOptions[] = {
        { "--unittest",             &runUnitTests },
        { "--no-windows-assert-ui", &quietWindowsAsserts },
        // Add additional command line option flags here
    };

    ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), true);

    if (quietWindowsAsserts) {
#ifdef Q_OS_WIN
        _CrtSetReportHook(WindowsCrtReportHook);
#endif
    }

    if (runUnitTests) {
        // Run the test
        int failures = AutoTest::run(argc-1, argv);
        if (failures == 0)
        {
            qDebug() << "ALL TESTS PASSED";
        }
        else
        {
            qDebug() << failures << " TESTS FAILED!";
        }
        return failures;
    }
#endif

    QGCCore* core = NULL;
    int val;
    bool firstStart = true;

    do {
        if (core) {
            delete core;
            firstStart = false;
        }
        core = new QGCCore(firstStart, argc, argv);
        val = core->exec();
    } while (core->getRestartRequested());

    return val;
}
<commit_msg>Add SSL check<commit_after>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Main executable
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QApplication>
#include <QSslSocket>

#include "QGCCore.h"
#include "MainWindow.h"
#include "configuration.h"
#include "SerialLink.h"
#include "TCPLink.h"
#ifdef QT_DEBUG
#include "AutoTest.h"
#include "CmdLineOptParser.h"
#ifdef Q_OS_WIN
#include <crtdbg.h>
#endif
#endif

/* SDL does ugly things to main() */
#ifdef main
#undef main
#endif

#ifdef Q_OS_WIN

/// @brief Message handler which is installed using qInstallMsgHandler so you do not need
/// the MSFT debug tools installed to see qDebug(), qWarning(), qCritical and qAbort
void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    const char symbols[] = { 'I', 'E', '!', 'X' };
    QString output = QString("[%1] at %2:%3 - \"%4\"").arg(symbols[type]).arg(context.file).arg(context.line).arg(msg);
    std::cerr << output.toStdString() << std::endl;
    if( type == QtFatalMsg ) abort();
}

/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when
/// we don't want asserts to pop a dialog on windows.
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
{
    Q_UNUSED(reportType);

    std::cerr << message << std::endl;  // Output message to stderr
    *returnValue = 0;                   // Don't break into debugger
    return true;                        // We handled this fully ourselves
}

#endif

/**
 * @brief Starts the application
 *
 * @param argc Number of commandline arguments
 * @param argv Commandline arguments
 * @return exit code, 0 for normal exit and !=0 for error cases
 */

int main(int argc, char *argv[])
{

#ifdef Q_OS_MAC
    // Prevent Apple's app nap from screwing us over
    // tip: the domain can be cross-checked on the command line with <defaults domains>
    QProcess::execute("defaults write org.qgroundcontrol.qgroundcontrol NSAppSleepDisabled -bool YES");
#endif

    // install the message handler
#ifdef Q_OS_WIN
    qInstallMessageHandler(msgHandler);
#endif

    // The following calls to qRegisterMetaType are done to silence debug output which warns
    // that we use these types in signals, and without calling qRegisterMetaType we can't queue
    // these signals. In general we don't queue these signals, but we do what the warning says
    // anyway to silence the debug output.
    qRegisterMetaType<QSerialPort::SerialPortError>();
    qRegisterMetaType<QAbstractSocket::SocketError>();

#ifdef QT_DEBUG
    // We parse a small set of command line options here prior to QGCCore in order to handle the ones
    // which need to be handled before a QApplication object is started.

    bool runUnitTests = false;          // Run unit test
    bool quietWindowsAsserts = false;   // Don't let asserts pop dialog boxes

    CmdLineOpt_t rgCmdLineOptions[] = {
        { "--unittest",             &runUnitTests },
        { "--no-windows-assert-ui", &quietWindowsAsserts },
        // Add additional command line option flags here
    };

    ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), true);

    if (quietWindowsAsserts) {
#ifdef Q_OS_WIN
        _CrtSetReportHook(WindowsCrtReportHook);
#endif
    }

    if (runUnitTests) {
        // Run the test
        int failures = AutoTest::run(argc-1, argv);
        if (failures == 0)
        {
            qDebug() << "ALL TESTS PASSED";
        }
        else
        {
            qDebug() << failures << " TESTS FAILED!";
        }
        return failures;
    }
#endif

    QGCCore* core = NULL;
    int val;
    bool firstStart = true;

    do {
        if (core) {
            delete core;
            firstStart = false;
        }
        core = new QGCCore(firstStart, argc, argv);

        if (!QSslSocket::supportsSsl()) {
            QMessageBox::critical(NULL,
                                  QObject::tr("Missing SSL Support"),
                                  QObject::tr("QGroundControl requires support for SSL to be installed prior to running. Please see http://www.qgroundcontrol.org/downloads for instructions on installing prerequisites for QGroundControl."));
            return 1;
        }

        val = core->exec();
    } while (core->getRestartRequested());

    return val;
}
<|endoftext|>


<commit_before>#include "Utility.h"

#include <vector>
#include <random>
#include <chrono>
#include <fstream>
#include <algorithm>
#include <string>
#include <cctype>
#include <iostream>
#include <cmath>

namespace String
{
    namespace
    {
        const auto whitespace = " \t\n";
    }
}

std::vector<std::string> String::split(const std::string& s, const std::string& delim, size_t count)
{
    std::vector<std::string> result;
    size_t start_index = 0;
    size_t end_index = 0;
    size_t split_count = 0;
    while(end_index < s.size() && split_count < count)
    {
        end_index = (delim.empty() ?
                     s.find_first_of(whitespace, start_index) :
                     s.find(delim, start_index));
        result.push_back(s.substr(start_index, end_index-start_index));
        if(end_index == std::string::npos)
        {
            start_index = std::string::npos;
        }
        else
        {
            start_index = end_index + (delim.empty() ? 1 : delim.size());
        }
        ++split_count;
    }

    if(start_index < s.size())
    {
        result.push_back(s.substr(start_index));
    }

    if(delim.empty())
    {
        auto it = result.begin();
        while(it != result.end())
        {
            if((*it).empty())
            {
                it = result.erase(it);
            }
            else
            {
                (*it) = String::trim_outer_whitespace(*it);
                ++it;
            }
        }
    }

    return result;
}

bool String::starts_with(const std::string& s, const std::string& beginning)
{
    return (beginning.size() <= s.size()) && std::equal(beginning.begin(), beginning.end(), s.begin());
}

bool String::starts_with(const std::string& s, char beginning)
{
    return ( ! s.empty()) && s[0] == beginning;
}

std::string String::consolidate_inner_whitespace(const std::string& s)
{
    if(s.empty())
    {
        return s;
    }
    size_t start = s.find_first_not_of(whitespace);
    auto initial_whitespace = s.substr(0, start);

    size_t last_non_whitespace = s.find_last_not_of(whitespace);
    std::string final_whitespace;
    if(last_non_whitespace != std::string::npos)
    {
        final_whitespace = s.substr(last_non_whitespace + 1);
    }

    std::string result;

    while(true)
    {
        auto end = s.find_first_of(whitespace, start);

        // [start, end) is all non-whitespace
        if( ! result.empty())
        {
            result += " ";
        }
        result += s.substr(start, end - start);
        start = s.find_first_not_of(whitespace, end);
        if(start == std::string::npos)
        {
            start = end; // only whitespace left
            break;
        }
    }

    return initial_whitespace + result + final_whitespace;
}

std::string String::trim_outer_whitespace(const std::string& s)
{
    auto text_start = s.find_first_not_of(whitespace);
    if(text_start == std::string::npos)
    {
        return std::string{};
    }

    auto text_end = s.find_last_not_of(whitespace);
    if(text_end == std::string::npos)
    {
        return s.substr(text_start);
    }

    return s.substr(text_start, text_end - text_start + 1);
}

std::string String::remove_extra_whitespace(const std::string& s)
{
    return trim_outer_whitespace(consolidate_inner_whitespace(s));
}

std::string String::strip_comments(const std::string& str, char comment)
{
    return trim_outer_whitespace(str.substr(0, str.find(comment)));
}

std::string String::strip_block_comment(const std::string& str, char start, char end)
{
    auto start_comment_index = str.find(start);
    auto end_comment_index = str.find(end);
    if(start_comment_index == std::string::npos || end_comment_index == std::string::npos)
    {
        return consolidate_inner_whitespace(trim_outer_whitespace(str));
    }

    auto first_part = str.substr(0, start_comment_index);
    auto last_part = str.substr(end_comment_index + 1);
    return strip_block_comment(first_part + " " + last_part, start, end);
}

std::string String::lowercase(std::string s)
{
    std::transform(s.begin(), s.end(), s.begin(), [](char c) -> char { return std::tolower(c); });
    return s;
}

int Random::random_integer(int min, int max)
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    using uid = std::uniform_int_distribution<int>;
    thread_local static auto dist = uid{};
    return dist(generator, uid::param_type{min, max});
}

double Random::random_laplace(double width)
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    using ed = std::exponential_distribution<double>;
    thread_local static auto dist = ed{};
    return (coin_flip() ? 1 : -1)*dist(generator, ed::param_type{width});
}

double Random::random_real(double min, double max)
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    using urd = std::uniform_real_distribution<double>;
    thread_local static auto dist = urd{};
    return dist(generator, urd::param_type{min, max});
}

uint64_t Random::random_unsigned_int64()
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    thread_local static std::uniform_int_distribution<uint64_t> dist;
    return dist(generator);
}

bool Random::coin_flip()
{
    return random_integer(0, 1) == 1;
}

bool Random::success_probability(double probability)
{
    return random_real(0.0, 1.0) < probability;
}

// Mean moves left in game given that a number of moves have been made already.
double Math::average_moves_left(double mean_moves, double width, size_t moves_so_far)
{
    // Assumes the number of moves in a game has a log-normal distribution.
    //
    // A = Sum(x = moves_so_far + 1 to infinity) P(x)*x = average number of moves
    //                                                    given game has already progressed
    //                                                    moves_so_far
    //
    // B = Sum(x = moves_so_far + 1 to infinity) P(x) = renormalization of P(x) for a
    //                                                  truncated range
    //
    // The calculations below for A and B use integrals on continuous functions as a
    // faster approximation.

    auto M = std::log(mean_moves);
    auto S = width;
    auto S2 = std::pow(S, 2);
    auto Sr2 = S*std::sqrt(2);
    auto ln_x = std::log(moves_so_far);

    auto A = std::exp(M + S2/2)*(1 + std::erf((M + S2 - ln_x)/Sr2));
    auto B = 1 + std::erf((M-ln_x)/Sr2);

    auto expected_mean = A/B;

    // If moves_so_far is much greater than mean_moves with a small
    // width in the log-normal distribution, A and B can end up
    // being zero, resulting in an undefined answer (NaN most likely).
    // This represents an extremely long game, so expect the game to end
    // soon.
    if( ! std::isfinite(expected_mean))
    {
        return 1.0;
    }

    return expected_mean - moves_so_far;
}

Configuration_File::Configuration_File(const std::string& file_name)
{
    std::ifstream ifs(file_name);
    std::string line;
    while(std::getline(ifs, line))
    {
        line = String::strip_comments(line, '#');
        if(line.empty())
        {
            continue;
        }
        if( ! String::contains(line, '='))
        {
            throw std::runtime_error("Configuration file lines must be of form \"Name = Value\"\n" + line);
        }
        auto line_split = String::split(line, "=", 1);
        auto parameter = String::lowercase(String::remove_extra_whitespace(line_split[0]));
        parameters[parameter] = String::trim_outer_whitespace(line_split[1]);
    }
}

std::string Configuration_File::get_text(const std::string& parameter) const
{
    try
    {
        return parameters.at(parameter);
    }
    catch(const std::out_of_range&)
    {
        for(const auto& key_value : parameters)
        {
            std::cerr << "\"" << key_value.first << "\" --> \"" << key_value.second << "\"" << std::endl;
        }
        throw std::runtime_error("Configuration parameter not found: " + parameter);
    }
}

double Configuration_File::get_number(const std::string& parameter) const
{
    try
    {
        return std::stod(get_text(parameter));
    }
    catch(const std::invalid_argument&)
    {
        throw std::runtime_error("Invalid number for \"" + parameter + "\" : " + get_text(parameter));
    }
}

std::ofstream Scoped_Stopwatch::out_file;
std::mutex Scoped_Stopwatch::write_lock;

Scoped_Stopwatch::Scoped_Stopwatch(const std::string& name) :
    place_name(name),
    start_time(std::chrono::steady_clock::now()),
    stopped(false)
{
}

Scoped_Stopwatch::~Scoped_Stopwatch()
{
    stop();
}

void Scoped_Stopwatch::stop()
{
    auto end_time = std::chrono::steady_clock::now();

    if(stopped)
    {
        return;
    }

    std::lock_guard<std::mutex> write_lock_guard(write_lock);

    if( ! out_file.is_open())
    {
        out_file.open("timings.txt");
    }

    out_file << place_name << "|"
             << std::chrono::duration_cast<std::chrono::duration<double>>
                (end_time - start_time).count()
             << '\n';

    stopped = true;
}

void Scoped_Stopwatch::add_info(const std::string& info)
{
    place_name += info;
}

void Scoped_Stopwatch::reject()
{
    stopped = true;
}
<commit_msg>Correct use of width parameter<commit_after>#include "Utility.h"

#include <vector>
#include <random>
#include <chrono>
#include <fstream>
#include <algorithm>
#include <string>
#include <cctype>
#include <iostream>
#include <cmath>

namespace String
{
    namespace
    {
        const auto whitespace = " \t\n";
    }
}

std::vector<std::string> String::split(const std::string& s, const std::string& delim, size_t count)
{
    std::vector<std::string> result;
    size_t start_index = 0;
    size_t end_index = 0;
    size_t split_count = 0;
    while(end_index < s.size() && split_count < count)
    {
        end_index = (delim.empty() ?
                     s.find_first_of(whitespace, start_index) :
                     s.find(delim, start_index));
        result.push_back(s.substr(start_index, end_index-start_index));
        if(end_index == std::string::npos)
        {
            start_index = std::string::npos;
        }
        else
        {
            start_index = end_index + (delim.empty() ? 1 : delim.size());
        }
        ++split_count;
    }

    if(start_index < s.size())
    {
        result.push_back(s.substr(start_index));
    }

    if(delim.empty())
    {
        auto it = result.begin();
        while(it != result.end())
        {
            if((*it).empty())
            {
                it = result.erase(it);
            }
            else
            {
                (*it) = String::trim_outer_whitespace(*it);
                ++it;
            }
        }
    }

    return result;
}

bool String::starts_with(const std::string& s, const std::string& beginning)
{
    return (beginning.size() <= s.size()) && std::equal(beginning.begin(), beginning.end(), s.begin());
}

bool String::starts_with(const std::string& s, char beginning)
{
    return ( ! s.empty()) && s[0] == beginning;
}

std::string String::consolidate_inner_whitespace(const std::string& s)
{
    if(s.empty())
    {
        return s;
    }
    size_t start = s.find_first_not_of(whitespace);
    auto initial_whitespace = s.substr(0, start);

    size_t last_non_whitespace = s.find_last_not_of(whitespace);
    std::string final_whitespace;
    if(last_non_whitespace != std::string::npos)
    {
        final_whitespace = s.substr(last_non_whitespace + 1);
    }

    std::string result;

    while(true)
    {
        auto end = s.find_first_of(whitespace, start);

        // [start, end) is all non-whitespace
        if( ! result.empty())
        {
            result += " ";
        }
        result += s.substr(start, end - start);
        start = s.find_first_not_of(whitespace, end);
        if(start == std::string::npos)
        {
            start = end; // only whitespace left
            break;
        }
    }

    return initial_whitespace + result + final_whitespace;
}

std::string String::trim_outer_whitespace(const std::string& s)
{
    auto text_start = s.find_first_not_of(whitespace);
    if(text_start == std::string::npos)
    {
        return std::string{};
    }

    auto text_end = s.find_last_not_of(whitespace);
    if(text_end == std::string::npos)
    {
        return s.substr(text_start);
    }

    return s.substr(text_start, text_end - text_start + 1);
}

std::string String::remove_extra_whitespace(const std::string& s)
{
    return trim_outer_whitespace(consolidate_inner_whitespace(s));
}

std::string String::strip_comments(const std::string& str, char comment)
{
    return trim_outer_whitespace(str.substr(0, str.find(comment)));
}

std::string String::strip_block_comment(const std::string& str, char start, char end)
{
    auto start_comment_index = str.find(start);
    auto end_comment_index = str.find(end);
    if(start_comment_index == std::string::npos || end_comment_index == std::string::npos)
    {
        return consolidate_inner_whitespace(trim_outer_whitespace(str));
    }

    auto first_part = str.substr(0, start_comment_index);
    auto last_part = str.substr(end_comment_index + 1);
    return strip_block_comment(first_part + " " + last_part, start, end);
}

std::string String::lowercase(std::string s)
{
    std::transform(s.begin(), s.end(), s.begin(), [](char c) -> char { return std::tolower(c); });
    return s;
}

int Random::random_integer(int min, int max)
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    using uid = std::uniform_int_distribution<int>;
    thread_local static auto dist = uid{};
    return dist(generator, uid::param_type{min, max});
}

double Random::random_laplace(double width)
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    using ed = std::exponential_distribution<double>;
    thread_local static auto dist = ed{};
    return (coin_flip() ? 1 : -1)*dist(generator, ed::param_type{1.0/width});
}

double Random::random_real(double min, double max)
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    using urd = std::uniform_real_distribution<double>;
    thread_local static auto dist = urd{};
    return dist(generator, urd::param_type{min, max});
}

uint64_t Random::random_unsigned_int64()
{
    thread_local static std::mt19937_64 generator(std::random_device{}());
    thread_local static std::uniform_int_distribution<uint64_t> dist;
    return dist(generator);
}

bool Random::coin_flip()
{
    return random_integer(0, 1) == 1;
}

bool Random::success_probability(double probability)
{
    return random_real(0.0, 1.0) < probability;
}

// Mean moves left in game given that a number of moves have been made already.
double Math::average_moves_left(double mean_moves, double width, size_t moves_so_far)
{
    // Assumes the number of moves in a game has a log-normal distribution.
    //
    // A = Sum(x = moves_so_far + 1 to infinity) P(x)*x = average number of moves
    //                                                    given game has already progressed
    //                                                    moves_so_far
    //
    // B = Sum(x = moves_so_far + 1 to infinity) P(x) = renormalization of P(x) for a
    //                                                  truncated range
    //
    // The calculations below for A and B use integrals on continuous functions as a
    // faster approximation.

    auto M = std::log(mean_moves);
    auto S = width;
    auto S2 = std::pow(S, 2);
    auto Sr2 = S*std::sqrt(2);
    auto ln_x = std::log(moves_so_far);

    auto A = std::exp(M + S2/2)*(1 + std::erf((M + S2 - ln_x)/Sr2));
    auto B = 1 + std::erf((M-ln_x)/Sr2);

    auto expected_mean = A/B;

    // If moves_so_far is much greater than mean_moves with a small
    // width in the log-normal distribution, A and B can end up
    // being zero, resulting in an undefined answer (NaN most likely).
    // This represents an extremely long game, so expect the game to end
    // soon.
    if( ! std::isfinite(expected_mean))
    {
        return 1.0;
    }

    return expected_mean - moves_so_far;
}

Configuration_File::Configuration_File(const std::string& file_name)
{
    std::ifstream ifs(file_name);
    std::string line;
    while(std::getline(ifs, line))
    {
        line = String::strip_comments(line, '#');
        if(line.empty())
        {
            continue;
        }
        if( ! String::contains(line, '='))
        {
            throw std::runtime_error("Configuration file lines must be of form \"Name = Value\"\n" + line);
        }
        auto line_split = String::split(line, "=", 1);
        auto parameter = String::lowercase(String::remove_extra_whitespace(line_split[0]));
        parameters[parameter] = String::trim_outer_whitespace(line_split[1]);
    }
}

std::string Configuration_File::get_text(const std::string& parameter) const
{
    try
    {
        return parameters.at(parameter);
    }
    catch(const std::out_of_range&)
    {
        for(const auto& key_value : parameters)
        {
            std::cerr << "\"" << key_value.first << "\" --> \"" << key_value.second << "\"" << std::endl;
        }
        throw std::runtime_error("Configuration parameter not found: " + parameter);
    }
}

double Configuration_File::get_number(const std::string& parameter) const
{
    try
    {
        return std::stod(get_text(parameter));
    }
    catch(const std::invalid_argument&)
    {
        throw std::runtime_error("Invalid number for \"" + parameter + "\" : " + get_text(parameter));
    }
}

std::ofstream Scoped_Stopwatch::out_file;
std::mutex Scoped_Stopwatch::write_lock;

Scoped_Stopwatch::Scoped_Stopwatch(const std::string& name) :
    place_name(name),
    start_time(std::chrono::steady_clock::now()),
    stopped(false)
{
}

Scoped_Stopwatch::~Scoped_Stopwatch()
{
    stop();
}

void Scoped_Stopwatch::stop()
{
    auto end_time = std::chrono::steady_clock::now();

    if(stopped)
    {
        return;
    }

    std::lock_guard<std::mutex> write_lock_guard(write_lock);

    if( ! out_file.is_open())
    {
        out_file.open("timings.txt");
    }

    out_file << place_name << "|"
             << std::chrono::duration_cast<std::chrono::duration<double>>
                (end_time - start_time).count()
             << '\n';

    stopped = true;
}

void Scoped_Stopwatch::add_info(const std::string& info)
{
    place_name += info;
}

void Scoped_Stopwatch::reject()
{
    stopped = true;
}
<|endoftext|>