<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/slobrok/sbmirror.h>
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/time.h>
#include <vespa/fastos/app.h>
#include <sys/time.h>
#include <thread>
#include <cstdlib>

#include <vespa/log/log.h>
LOG_SETUP("vespa-proton-cmd");

namespace pandora::rtc_cmd {

class App : public FastOS_Application
{
private:
    App(const App &);
    App& operator=(const App &);

    std::unique_ptr<fnet::frt::StandaloneFRT> _frt;
    FRT_Target     *_target;
    FRT_RPCRequest *_req;

public:
    App()
        : _frt(),
          _target(nullptr),
          _req(nullptr)
    {}
    ~App() override
    {
        assert(!_frt);
        assert(_target == nullptr);
        assert(_req == nullptr);
    }

    int usage()
    {
        fprintf(stderr, "usage: %s <port|spec|--local|--id=name> <cmd> [args]\n", _argv[0]);
        fprintf(stderr, "die\n");
        fprintf(stderr, "getProtonStatus\n");
        fprintf(stderr, "getState\n");
        fprintf(stderr, "monitor\n");
        fprintf(stderr, "triggerFlush\n");
        fprintf(stderr, "prepareRestart\n");
        return 1;
    }

    void initRPC()
    {
        _frt = std::make_unique<fnet::frt::StandaloneFRT>();
        _req = _frt->supervisor().AllocRPCRequest();
    }

    void invokeRPC(bool print, double timeout=5.0)
    {
        if (_req == nullptr)
            return;

        _target->InvokeSync(_req, timeout);
        if (print || _req->IsError())
            _req->Print(0);
    }

    void finiRPC()
    {
        if (_req != nullptr) {
            _req->SubRef();
            _req = nullptr;
        }
        if (_target != nullptr) {
            _target->SubRef();
            _target = nullptr;
        }
        if (_frt) {
            _frt.reset();
        }
    }

    void
    monitorLoop();

    void
    scanSpecs(slobrok::api::MirrorAPI::SpecList &specs,
              const std::string &me,
              std::string &service,
              std::string &spec,
              int &found)
    {
        for (size_t j = 0; j < specs.size(); ++j) {
            if (specs[j].first == service)
                continue;
            if (specs[j].second.compare(0, me.length(), me) == 0) {
                service = specs[j].first;
                spec = specs[j].second;
                printf("found local RTC '%s' with connection spec %s\n",
                       specs[j].first.c_str(), spec.c_str());
                ++found;
            }
        }
    }

    std::string findRTC() {
        std::string me = "tcp/";
        me += vespalib::HostName::get().c_str();
        me += ":";

        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";
        std::string rtcPattern2 = "*/search/cluster.*/*/realtimecontroller";
        std::string rtcPattern3 = "*/search/*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                fprintf(stderr,
                        "ERROR: no data from service location broker\n");
                std::_Exit(1);
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(rtcPattern);
            slobrok::api::MirrorAPI::SpecList specs2 = sbmirror.lookup(rtcPattern2);
            slobrok::api::MirrorAPI::SpecList specs3 = sbmirror.lookup(rtcPattern3);

            int found = 0;
            std::string service;
            std::string spec;

            printf("looking for RTCs matching '%s' (length %d)\n",
                   me.c_str(), (int)me.length());
            scanSpecs(specs, me, service, spec, found);
            scanSpecs(specs2, me, service, spec, found);
            scanSpecs(specs3, me, service, spec, found);
            if (found > 1) {
                fprintf(stderr, "found more than one local RTC, you must use --id=<name>\n");
                std::_Exit(1);
            }
            if (found < 1) {
                fprintf(stderr, "found no local RTC, you must use --id=<name> (list follows):\n");
                for (size_t j = 0; j < specs.size(); ++j) {
                    printf("RTC name %s with connection spec %s\n",
                           specs[j].first.c_str(), specs[j].second.c_str());
                }
                std::_Exit(1);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            fprintf(stderr, "ERROR: failed to get service location broker configuration\n");
            std::_Exit(1);
        } catch (vespalib::IllegalStateException& e) {
            fprintf(stderr, "ERROR: empty or invalid service location broker configuration\n");
            std::_Exit(2);
        }
        return "";
    }

    std::string findRTC(std::string id) {
        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                throw std::runtime_error("ERROR: no data from service location broker");
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(id);

            int found = 0;
            std::string spec;

            for (size_t j = 0; j < specs.size(); ++j) {
                std::string name = specs[j].first;
                spec = specs[j].second;
                printf("found RTC '%s' with connection spec %s\n",
                       name.c_str(), spec.c_str());
                ++found;
            }
            if (found > 1) {
                throw std::runtime_error("found more than one RTC, use a more specific id");
            }
            if (found < 1) {
                specs = sbmirror.lookup(rtcPattern);

                std::string msg = vespalib::make_string("found no RTC named '%s' (list follows):\n", id.c_str());
                for (size_t j = 0; j < specs.size(); ++j) {
                    msg += vespalib::make_string("RTC name %s with connection spec %s\n", specs[j].first.c_str(), specs[j].second.c_str());
                }
                throw std::runtime_error(msg);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            throw std::runtime_error("ERROR: failed to get service location broker configuration");
        }
        return "";
    }

    int Main() override
    {
        if (_argc < 3) {
            return usage();
        }

        config::ConfigSystem configSystem;
        if (!configSystem.isUp()) {
            fprintf(stderr, "Config system is not up. Verify that vespa is started.");
            return 3;
        }
        try {
            initRPC();
        } catch (vespalib::Exception &e) {
            fprintf(stderr, "Exception in network initialization: %s", e.what());
            return 2;
        }
        int port = 0;
        std::string spec = _argv[1];

        try {
            if (spec == "--local") {
                spec = findRTC();
            } else if (spec.compare(0, 5, "--id=") == 0) {
                spec = findRTC(spec.substr(5));
            } else {
                port = atoi(_argv[1]);
            }
        } catch (const std::runtime_error & e) {
            fprintf(stderr, "%s", e.what());
            finiRPC();
            return 1;
        } catch (const config::ConfigTimeoutException & e) {
            fprintf(stderr, "Getting config timed out: %s", e.what());
            finiRPC();
            return 2;
        }

        if (port == 0 && spec.compare(0, 4, "tcp/") != 0) {
            finiRPC();
            return usage();
        }

        if (port != 0) {
            _target = _frt->supervisor().GetTarget(port);
        } else {
            _target = _frt->supervisor().GetTarget(spec.c_str());
        }

        bool invoked = false;

        if (strcmp(_argv[2], "getState") == 0 &&
                   _argc >= 3) {
            _req->SetMethodName("pandora.rtc.getState");

            FRT_Values &params = *_req->GetParams();

            params.AddInt32(_argc > 3 ? atoi(_argv[3]) : 0);
            params.AddInt32(_argc > 4 ? atoi(_argv[4]) : 0);
            invokeRPC(false);
            invoked = true;

            FRT_Values &rvals = *_req->GetReturn();

            if (!_req->IsError()) {
                FRT_Value &names = rvals.GetValue(0);
                FRT_Value &values = rvals.GetValue(1);
                FRT_Value &gencnt = rvals.GetValue(2);

                for (unsigned int i = 0;
                     i < names._string_array._len &&
                                      i < values._string_array._len;
                     i++)
                {
                    printf("\"%s\", \"%s\"\n",
                           names._string_array._pt[i]._str,
                           values._string_array._pt[i]._str);
                }
                printf("gencnt=%u\n",
                       static_cast<unsigned int>(gencnt._intval32));
            }
        } else if (strcmp(_argv[2], "getProtonStatus") == 0 &&
                   _argc >= 3) {

            _req->SetMethodName("proton.getStatus");
            FRT_Values &params = *_req->GetParams();
            params.AddString(_argc > 3 ? _argv[3] : "");
            invokeRPC(false);
            invoked = true;
            FRT_Values &rvals = *_req->GetReturn();
            if (!_req->IsError()) {
                FRT_Value &components = rvals.GetValue(0);
                FRT_Value &states = rvals.GetValue(1);
                FRT_Value &internalStates = rvals.GetValue(2);
                FRT_Value &messages = rvals.GetValue(3);
                for (unsigned int i = 0; i < components._string_array._len &&
                                         i < states._string_array._len &&
                                         i < internalStates.
                                               _string_array._len &&
                                         i < messages._string_array._len;
                                       i++) {
                    printf("\"%s\",\"%s\",\"%s\",\"%s\"\n",
                           components._string_array._pt[i]._str,
                           states._string_array._pt[i]._str,
                           internalStates._string_array._pt[i]._str,
                           messages._string_array._pt[i]._str);
                }

            }
        } else if (strcmp(_argv[2], "triggerFlush") == 0) {
            _req->SetMethodName("proton.triggerFlush");
            invokeRPC(false, 86400.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: flush trigger enabled\n");
            }
        } else if (strcmp(_argv[2], "prepareRestart") == 0) {
            _req->SetMethodName("proton.prepareRestart");
            invokeRPC(false, 600.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: prepareRestart enabled\n");
            }
        } else if (strcmp(_argv[2], "die") == 0) {
            _req->SetMethodName("pandora.rtc.die");

        } else if (strcmp(_argv[2], "monitor") == 0) {
            invoked = true;
            monitorLoop();
        } else {
            finiRPC();
            return usage();
        }
        if (!invoked)
            invokeRPC(true);
        finiRPC();
        return 0;
    }
};

void
App::monitorLoop()
{
    for (;;) {
        FRT_RPCRequest *req = _frt->supervisor().AllocRPCRequest();
        req->SetMethodName("pandora.rtc.getIncrementalState");
        FRT_Values &params = *req->GetParams();
        params.AddInt32(2000);
        _target->InvokeSync(req, 1200.0);

        if (req->IsError()) {
            req->Print(0);
            req->SubRef();
            break;
        }
        FRT_Values &rvals = *req->GetReturn();
        FRT_Value &names = rvals.GetValue(0);
        FRT_Value &values = rvals.GetValue(1);
        struct timeval tnow;
        gettimeofday(&tnow, nullptr);

        for (unsigned int i = 0;
             i < names._string_array._len &&
                              i < values._string_array._len;
             i++)
        {
            time_t now;
            struct tm *nowtm;

            now = tnow.tv_sec;
            nowtm = gmtime(&now);
            fprintf(stdout,
                    "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ "
                    "%010d.%06d ==> ",
                    nowtm->tm_year + 1900,
                    nowtm->tm_mon + 1,
                    nowtm->tm_mday,
                    nowtm->tm_hour,
                    nowtm->tm_min,
                    nowtm->tm_sec,
                    (int)tnow.tv_usec,
                    (int)tnow.tv_sec,
                    (int) tnow.tv_usec);
            printf("\"%s\", \"%s\"\n",
                   names._string_array._pt[i]._str,
                   values._string_array._pt[i]._str);
        }
        fflush(stdout);
        req->SubRef();
    }
}

} // namespace pandora::rtc_cmd

int main(int argc, char **argv)
{
    pandora::rtc_cmd::App app;
    return app.Entry(argc, argv);
}
<commit_msg>Add exception info.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/slobrok/sbmirror.h>
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/time.h>
#include <vespa/fastos/app.h>
#include <sys/time.h>
#include <thread>
#include <cstdlib>

#include <vespa/log/log.h>
LOG_SETUP("vespa-proton-cmd");

namespace pandora::rtc_cmd {

class App : public FastOS_Application
{
private:
    App(const App &);
    App& operator=(const App &);

    std::unique_ptr<fnet::frt::StandaloneFRT> _frt;
    FRT_Target     *_target;
    FRT_RPCRequest *_req;

public:
    App()
        : _frt(),
          _target(nullptr),
          _req(nullptr)
    {}
    ~App() override
    {
        assert(!_frt);
        assert(_target == nullptr);
        assert(_req == nullptr);
    }

    int usage()
    {
        fprintf(stderr, "usage: %s <port|spec|--local|--id=name> <cmd> [args]\n", _argv[0]);
        fprintf(stderr, "die\n");
        fprintf(stderr, "getProtonStatus\n");
        fprintf(stderr, "getState\n");
        fprintf(stderr, "monitor\n");
        fprintf(stderr, "triggerFlush\n");
        fprintf(stderr, "prepareRestart\n");
        return 1;
    }

    void initRPC()
    {
        _frt = std::make_unique<fnet::frt::StandaloneFRT>();
        _req = _frt->supervisor().AllocRPCRequest();
    }

    void invokeRPC(bool print, double timeout=5.0)
    {
        if (_req == nullptr)
            return;

        _target->InvokeSync(_req, timeout);
        if (print || _req->IsError())
            _req->Print(0);
    }

    void finiRPC()
    {
        if (_req != nullptr) {
            _req->SubRef();
            _req = nullptr;
        }
        if (_target != nullptr) {
            _target->SubRef();
            _target = nullptr;
        }
        if (_frt) {
            _frt.reset();
        }
    }

    void
    monitorLoop();

    void
    scanSpecs(slobrok::api::MirrorAPI::SpecList &specs,
              const std::string &me,
              std::string &service,
              std::string &spec,
              int &found)
    {
        for (size_t j = 0; j < specs.size(); ++j) {
            if (specs[j].first == service)
                continue;
            if (specs[j].second.compare(0, me.length(), me) == 0) {
                service = specs[j].first;
                spec = specs[j].second;
                printf("found local RTC '%s' with connection spec %s\n",
                       specs[j].first.c_str(), spec.c_str());
                ++found;
            }
        }
    }

    std::string findRTC() {
        std::string me = "tcp/";
        me += vespalib::HostName::get().c_str();
        me += ":";

        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";
        std::string rtcPattern2 = "*/search/cluster.*/*/realtimecontroller";
        std::string rtcPattern3 = "*/search/*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                fprintf(stderr,
                        "ERROR: no data from service location broker\n");
                std::_Exit(1);
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(rtcPattern);
            slobrok::api::MirrorAPI::SpecList specs2 = sbmirror.lookup(rtcPattern2);
            slobrok::api::MirrorAPI::SpecList specs3 = sbmirror.lookup(rtcPattern3);

            int found = 0;
            std::string service;
            std::string spec;

            printf("looking for RTCs matching '%s' (length %d)\n",
                   me.c_str(), (int)me.length());
            scanSpecs(specs, me, service, spec, found);
            scanSpecs(specs2, me, service, spec, found);
            scanSpecs(specs3, me, service, spec, found);
            if (found > 1) {
                fprintf(stderr, "found more than one local RTC, you must use --id=<name>\n");
                std::_Exit(1);
            }
            if (found < 1) {
                fprintf(stderr, "found no local RTC, you must use --id=<name> (list follows):\n");
                for (size_t j = 0; j < specs.size(); ++j) {
                    printf("RTC name %s with connection spec %s\n",
                           specs[j].first.c_str(), specs[j].second.c_str());
                }
                std::_Exit(1);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            fprintf(stderr, "ERROR: failed to get service location broker configuration\n");
            std::_Exit(1);
        } catch (vespalib::IllegalStateException& e) {
            fprintf(stderr, "ERROR: empty or invalid service location broker configuration: %s\n", e.what());
            std::_Exit(2);
        }
        return "";
    }

    std::string findRTC(std::string id) {
        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                throw std::runtime_error("ERROR: no data from service location broker");
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(id);

            int found = 0;
            std::string spec;

            for (size_t j = 0; j < specs.size(); ++j) {
                std::string name = specs[j].first;
                spec = specs[j].second;
                printf("found RTC '%s' with connection spec %s\n",
                       name.c_str(), spec.c_str());
                ++found;
            }
            if (found > 1) {
                throw std::runtime_error("found more than one RTC, use a more specific id");
            }
            if (found < 1) {
                specs = sbmirror.lookup(rtcPattern);

                std::string msg = vespalib::make_string("found no RTC named '%s' (list follows):\n", id.c_str());
                for (size_t j = 0; j < specs.size(); ++j) {
                    msg += vespalib::make_string("RTC name %s with connection spec %s\n", specs[j].first.c_str(), specs[j].second.c_str());
                }
                throw std::runtime_error(msg);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            throw std::runtime_error("ERROR: failed to get service location broker configuration");
        }
        return "";
    }

    int Main() override
    {
        if (_argc < 3) {
            return usage();
        }

        config::ConfigSystem configSystem;
        if (!configSystem.isUp()) {
            fprintf(stderr, "Config system is not up. Verify that vespa is started.");
            return 3;
        }
        try {
            initRPC();
        } catch (vespalib::Exception &e) {
            fprintf(stderr, "Exception in network initialization: %s", e.what());
            return 2;
        }
        int port = 0;
        std::string spec = _argv[1];

        try {
            if (spec == "--local") {
                spec = findRTC();
            } else if (spec.compare(0, 5, "--id=") == 0) {
                spec = findRTC(spec.substr(5));
            } else {
                port = atoi(_argv[1]);
            }
        } catch (const std::runtime_error & e) {
            fprintf(stderr, "%s", e.what());
            finiRPC();
            return 1;
        } catch (const config::ConfigTimeoutException & e) {
            fprintf(stderr, "Getting config timed out: %s", e.what());
            finiRPC();
            return 2;
        }

        if (port == 0 && spec.compare(0, 4, "tcp/") != 0) {
            finiRPC();
            return usage();
        }

        if (port != 0) {
            _target = _frt->supervisor().GetTarget(port);
        } else {
            _target = _frt->supervisor().GetTarget(spec.c_str());
        }

        bool invoked = false;

        if (strcmp(_argv[2], "getState") == 0 &&
                   _argc >= 3) {
            _req->SetMethodName("pandora.rtc.getState");

            FRT_Values &params = *_req->GetParams();

            params.AddInt32(_argc > 3 ? atoi(_argv[3]) : 0);
            params.AddInt32(_argc > 4 ? atoi(_argv[4]) : 0);
            invokeRPC(false);
            invoked = true;

            FRT_Values &rvals = *_req->GetReturn();

            if (!_req->IsError()) {
                FRT_Value &names = rvals.GetValue(0);
                FRT_Value &values = rvals.GetValue(1);
                FRT_Value &gencnt = rvals.GetValue(2);

                for (unsigned int i = 0;
                     i < names._string_array._len &&
                                      i < values._string_array._len;
                     i++)
                {
                    printf("\"%s\", \"%s\"\n",
                           names._string_array._pt[i]._str,
                           values._string_array._pt[i]._str);
                }
                printf("gencnt=%u\n",
                       static_cast<unsigned int>(gencnt._intval32));
            }
        } else if (strcmp(_argv[2], "getProtonStatus") == 0 &&
                   _argc >= 3) {

            _req->SetMethodName("proton.getStatus");
            FRT_Values &params = *_req->GetParams();
            params.AddString(_argc > 3 ? _argv[3] : "");
            invokeRPC(false);
            invoked = true;
            FRT_Values &rvals = *_req->GetReturn();
            if (!_req->IsError()) {
                FRT_Value &components = rvals.GetValue(0);
                FRT_Value &states = rvals.GetValue(1);
                FRT_Value &internalStates = rvals.GetValue(2);
                FRT_Value &messages = rvals.GetValue(3);
                for (unsigned int i = 0; i < components._string_array._len &&
                                         i < states._string_array._len &&
                                         i < internalStates.
                                               _string_array._len &&
                                         i < messages._string_array._len;
                                       i++) {
                    printf("\"%s\",\"%s\",\"%s\",\"%s\"\n",
                           components._string_array._pt[i]._str,
                           states._string_array._pt[i]._str,
                           internalStates._string_array._pt[i]._str,
                           messages._string_array._pt[i]._str);
                }

            }
        } else if (strcmp(_argv[2], "triggerFlush") == 0) {
            _req->SetMethodName("proton.triggerFlush");
            invokeRPC(false, 86400.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: flush trigger enabled\n");
            }
        } else if (strcmp(_argv[2], "prepareRestart") == 0) {
            _req->SetMethodName("proton.prepareRestart");
            invokeRPC(false, 600.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: prepareRestart enabled\n");
            }
        } else if (strcmp(_argv[2], "die") == 0) {
            _req->SetMethodName("pandora.rtc.die");

        } else if (strcmp(_argv[2], "monitor") == 0) {
            invoked = true;
            monitorLoop();
        } else {
            finiRPC();
            return usage();
        }
        if (!invoked)
            invokeRPC(true);
        finiRPC();
        return 0;
    }
};

void
App::monitorLoop()
{
    for (;;) {
        FRT_RPCRequest *req = _frt->supervisor().AllocRPCRequest();
        req->SetMethodName("pandora.rtc.getIncrementalState");
        FRT_Values &params = *req->GetParams();
        params.AddInt32(2000);
        _target->InvokeSync(req, 1200.0);

        if (req->IsError()) {
            req->Print(0);
            req->SubRef();
            break;
        }
        FRT_Values &rvals = *req->GetReturn();
        FRT_Value &names = rvals.GetValue(0);
        FRT_Value &values = rvals.GetValue(1);
        struct timeval tnow;
        gettimeofday(&tnow, nullptr);

        for (unsigned int i = 0;
             i < names._string_array._len &&
                              i < values._string_array._len;
             i++)
        {
            time_t now;
            struct tm *nowtm;

            now = tnow.tv_sec;
            nowtm = gmtime(&now);
            fprintf(stdout,
                    "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ "
                    "%010d.%06d ==> ",
                    nowtm->tm_year + 1900,
                    nowtm->tm_mon + 1,
                    nowtm->tm_mday,
                    nowtm->tm_hour,
                    nowtm->tm_min,
                    nowtm->tm_sec,
                    (int)tnow.tv_usec,
                    (int)tnow.tv_sec,
                    (int) tnow.tv_usec);
            printf("\"%s\", \"%s\"\n",
                   names._string_array._pt[i]._str,
                   values._string_array._pt[i]._str);
        }
        fflush(stdout);
        req->SubRef();
    }
}

} // namespace pandora::rtc_cmd

int main(int argc, char **argv)
{
    pandora::rtc_cmd::App app;
    return app.Entry(argc, argv);
}
<|endoftext|>


<commit_before>/**
    @file Frame.hpp
    @brief Manages the frame of the game.
    @copyright LGPL. MIT License.
*/

#ifndef __FRAME__
#define __FRAME__

#include "Engine/sdl2include.hpp"

class Frame {
public:
    Frame(int positionX, int positionY, int width, int height);
    SDL_Rect *GetRect();

private:
    // Rectangular area of the frame
    SDL_Rect sourceRectangle;
};

#endif // __FRAME__
<commit_msg>First application of initializing variables when declaring technique - Applied  in Frame class<commit_after>/**
    @file Frame.hpp
    @brief Manages the frame of the game.
    @copyright LGPL. MIT License.
*/

#ifndef __FRAME__
#define __FRAME__

#include "Engine/sdl2include.hpp"

class Frame {
public:
    Frame(int positionX, int positionY, int width, int height);
    SDL_Rect *GetRect();

private:
    // Rectangular area of the frame
    SDL_Rect sourceRectangle = {0, 0, 0, 0};
};

#endif // __FRAME__
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    updateButton(new QtAutoUpdater::UpdateButton(this)) //add this for the updater
{
    ui->setupUi(this);

    updateButton->setVisible(false); //The updateButton is not visible
    initializeUpdater();	//Initialize the updater

    controller->start(QtAutoUpdater::UpdateController::InfoLevel);	//Search for updates. Display a message if updates found, otherwise do nothing

    //Connect the checkUpdateButton button to the checkUpdate method (starts the update check process)
    connect(ui->checkUpdateButton, &QAbstractButton::clicked, this, &MainWindow::checkUpdate);

    //Connect the actionCheck_for_updates_2 to the method (starts the update check process)
    connect(ui->actionCheck_for_updates_2, &QAction::triggered, this, &MainWindow::checkUpdate);
}

MainWindow::~MainWindow()
{
    delete controller;
    delete updateButton;
    delete ui;
}

//Initialize the updater
void MainWindow::initializeUpdater()
{
    controller = new QtAutoUpdater::UpdateController("maintenancetool.exe", qApp);	//Updater app name
    if(ui->checkBox_showDetailledUpdateInformations->isChecked()) controller->setDetailedUpdateInfo(true);  //If checkbox is checked, show detailled update infos
    else controller->setDetailedUpdateInfo(false);

    updateButton->setController(controller);
}

//Starts update check process
void MainWindow::checkUpdate()
{
    if(ui->checkBox_showDetailledUpdateInformations->isChecked()) controller->setDetailedUpdateInfo(true);  //If checkbox is checked, show detailled update infos
    else controller->setDetailedUpdateInfo(false);
    controller->start(QtAutoUpdater::UpdateController::ProgressLevel);	//Check for updates. Displays a progress bar when searching
}
<commit_msg>Update mainwindow.cpp<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    updateButton(new QtAutoUpdater::UpdateButton(this)) //add this for the updater
{
    ui->setupUi(this);

    updateButton->setVisible(false); //The updateButton is not visible
    initializeUpdater();	//Initialize the updater

    controller->start(QtAutoUpdater::UpdateController::InfoLevel);	//Search for updates. Display a message if updates found, otherwise do nothing

    //Connect the checkUpdateButton button to the checkUpdate method (starts the update check process)
    connect(ui->checkUpdateButton, &QAbstractButton::clicked, this, &MainWindow::checkUpdate);

    //Connect the actionCheck_for_updates_2 to the method (starts the update check process)
    connect(ui->actionCheck_for_updates_2, &QAction::triggered, this, &MainWindow::checkUpdate);
}

MainWindow::~MainWindow()
{
    delete controller;
    delete updateButton;
    delete ui;
}

//Initialize the updater
void MainWindow::initializeUpdater()
{
    controller = new QtAutoUpdater::UpdateController(QStringLiteral("maintenancetool.exe"), qApp);	//Updater app name
    if(ui->checkBox_showDetailledUpdateInformations->isChecked()) controller->setDetailedUpdateInfo(true);  //If checkbox is checked, show detailled update infos
    else controller->setDetailedUpdateInfo(false);

    updateButton->setController(controller);
}

//Starts update check process
void MainWindow::checkUpdate()
{
    if(ui->checkBox_showDetailledUpdateInformations->isChecked()) controller->setDetailedUpdateInfo(true);  //If checkbox is checked, show detailled update infos
    else controller->setDetailedUpdateInfo(false);
    controller->start(QtAutoUpdater::UpdateController::ProgressLevel);	//Check for updates. Displays a progress bar when searching
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009-2014 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <common/buffer.h>
#include <common/endian.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_cache.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_hash.h>

struct candidate_symbol {
	bool set_;
	unsigned offset_;
	uint64_t symbol_;
};

XCodecEncoder::XCodecEncoder(XCodecCache *cache)
: log_("/xcodec/encoder"),
  cache_(cache),
  window_(),
  stream_(!cache_->out_of_band())
{ }

XCodecEncoder::~XCodecEncoder()
{ }

/*
 * This takes a view of a data stream and turns it into a series of references
 * to other data, declarations of data to be referenced, and data that needs
 * escaped.
 *
 * The caller may request to retain a map of hashes and segments referenced by
 * this stream, a "refmap".
 *
 * Note that although each refmap is local to the frame referencing it, there
 * is still an issue with how hash reuse within even a single call to this
 * function could occur.  Consider the case of a memory cache limited to 2-3
 * segments.  When a colliding chunk of data is discovered, we will collide
 * within the refmap due to eviction.  The stream's decoding should be
 * decidable, but it is so only if we track an ordered listing of each
 * reference in order and the data it corresponds to and have some way of
 * identifying <ASK>/<LEARN> type requests linearly.  Another solution is
 * needed here, namely to just fail and fail tremendously when we have such
 * a malformed stream of data that we can't guarantee its decoding.  Or we
 * may just want to check the refmap in addition to the backing cache (and
 * maybe in preference to it) to prevent this problem.  But that shifts part
 * of the burden for correct decoding to the decoder, which then has to be
 * more careful about assuming that a <LEARN> covers all of the data it is
 * trying to decode which requests a hash, rather than just one frame.
 */
void
XCodecEncoder::encode(Buffer *output, Buffer *input, std::map<uint64_t, BufferSegment *> *refmap)
{
	if (input->empty())
		return;

	if (input->length() < XCODEC_SEGMENT_LENGTH) {
		encode_escape(output, input, input->length());
		return;
	}

	XCodecHash xcodec_hash;
	candidate_symbol candidate;
	Buffer outq;
	unsigned o = 0;

	candidate.set_ = false;

	/*
	 * While there is input.
	 */
	while (!input->empty()) {
		/*
		 * If we cannot acquire a complete hash within this segment,
		 * stop looking.
		 */
		if (o + input->length() < XCODEC_SEGMENT_LENGTH) {
			input->moveout(&outq);
			break;
		}

		/*
		 * Take the first BufferSegment out of the input Buffer.
		 */
		BufferSegment *seg;
		input->moveout(&seg);

		/*
		 * And add it to a temporary Buffer where input is queued.
		 */
		outq.append(seg);

		/*
		 * And for every byte in this BufferSegment.
		 */
		const uint8_t *p, *q = seg->end();
		for (p = seg->data(); p < q; p++) {
			ptrdiff_t resid = q - p;

			/*
			 * If we cannot acquire a complete hash within this segment.
			 */
			if (o + resid < XCODEC_SEGMENT_LENGTH) {
				/*
				 * Hash all of the bytes from it and continue.
				 */
				o += resid;
				while (p < q)
					xcodec_hash.add(*p++);
				break;
			}

			/*
			 * If we don't have a complete hash.
			 */
			if (o < XCODEC_SEGMENT_LENGTH) {
				for (;;) {
					/*
					 * Add bytes to the hash.
					 */
					xcodec_hash.add(*p);

					/*
					 * Until we have a complete hash.
					 */
					if (++o == XCODEC_SEGMENT_LENGTH)
						break;

					/*
					 * Go to the next byte.
					 */
					p++;
				}
				ASSERT(log_, o == XCODEC_SEGMENT_LENGTH);
			} else {
				/*
				 * Roll it into the rolling hash.
				 */
				xcodec_hash.roll(*p);
				o++;
			}

			ASSERT(log_, o >= XCODEC_SEGMENT_LENGTH);
			ASSERT(log_, p != q);

			/*
			 * And then mix the hash's internal state into a
			 * uint64_t that we can use to refer to that data
			 * and to look up possible past occurances of that
			 * data in the XCodecCache.
			 */
			unsigned start = o - XCODEC_SEGMENT_LENGTH;
			uint64_t hash = xcodec_hash.mix();

			/*
			 * If there is a pending candidate hash that wouldn't
			 * overlap with the data that the rolling hash presently
			 * covers, declare it now.
			 */
			if (candidate.set_ && candidate.offset_ + XCODEC_SEGMENT_LENGTH <= start) {
				BufferSegment *nseg;
				encode_declaration(output, &outq, candidate.offset_, candidate.symbol_, &nseg, refmap);

				o -= candidate.offset_ + XCODEC_SEGMENT_LENGTH;
				start = o - XCODEC_SEGMENT_LENGTH;

				candidate.set_ = false;

				/*
				 * If, on top of that, the just-declared hash is
				 * the same as the current hash, consider referencing
				 * it immediately.
				 */
				if (hash == candidate.symbol_) {
					/*
					 * If it's a hash collision, though, nevermind.
					 * Skip trying to use this hash as a reference,
					 * too, and go on to the next one.
					 */
					if (!encode_reference(output, &outq, start, hash, nseg, refmap)) {
						nseg->unref();
						DEBUG(log_) << "Collision in adjacent-declare pass.";
						continue;
					}
					nseg->unref();

					/*
					 * But if there's no collection, then we can move
					 * on to looking for the *next* hash/data to declare
					 * or reference.
					 */
					o = 0;
					xcodec_hash.reset();

					DEBUG(log_) << "Hit in adjacent-declare pass.";
					continue;
				}
				nseg->unref();
			}

			/*
			 * Now attempt to encode this hash as a reference if it
			 * has been defined before.
			 */
			if (find_reference(output, &outq, start, hash, refmap)) {
				o = 0;
				xcodec_hash.reset();

				/*
				 * We have output any data before this hash
				 * in escaped form, so any candidate hash
				 * before it is invalid now.
				 */
				candidate.set_ = false;
				continue;
			}

			/*
			 * Not defined before, it's a candidate for declaration
			 * if we don't already have one.
			 */
			if (candidate.set_) {
				/*
				 * We already have a hash that occurs earlier,
				 * isn't a collision and includes data that's
				 * covered by this hash, so don't remember it
				 * and keep going.
				 */
				ASSERT(log_, candidate.offset_ + XCODEC_SEGMENT_LENGTH > start);
				continue;
			}

			/*
			 * The hash at this offset doesn't collide with any
			 * other and is the first viable hash we've seen so far
			 * in the stream, so remember it so that if we don't
			 * find something to reference we can declare this one
			 * for future use.
			 */
			candidate.offset_ = start;
			candidate.symbol_ = hash;
			candidate.set_ = true;
		}

		seg->unref();
	}

	/*
	 * Done processing input.  If there's still data in the outq Buffer,
	 * then we need to declare any candidate hashes and escape any data
	 * after them.
	 */

	/*
	 * There's a hash we can declare, do it.
	 */
	if (candidate.set_) {
		ASSERT(log_, !outq.empty());
		encode_declaration(output, &outq, candidate.offset_, candidate.symbol_, NULL, refmap);
		candidate.set_ = false;
	}

	/*
	 * There's data after that hash or no candidate hash, so
	 * just escape it.
	 */
	if (!outq.empty()) {
		encode_escape(output, &outq, outq.length());
	}

	ASSERT(log_, !candidate.set_);
	ASSERT(log_, outq.empty());
	ASSERT(log_, input->empty());
}

void
XCodecEncoder::encode_declaration(Buffer *output, Buffer *input, unsigned offset, uint64_t hash, BufferSegment **segp, std::map<uint64_t, BufferSegment *> *refmap)
{
	if (offset != 0) {
		encode_escape(output, input, offset);
	}

	BufferSegment *nseg;
	input->copyout(&nseg, XCODEC_SEGMENT_LENGTH);

	cache_->enter(hash, nseg);

	if (!stream_) {
		/*
		 * Declarations occur out-of-band.
		 */
		if (!encode_reference(output, input, 0, hash, nseg, refmap)) /* XXX Pass NULL not nseg to skip check?  */
			NOTREACHED(log_);
		if (segp == NULL)
			nseg->unref();
		else
			*segp = nseg;
		return;
	}

	/*
	 * Declarations are extracted in-band.
	 */
	output->append(XCODEC_MAGIC);
	output->append(XCODEC_OP_EXTRACT);
	output->append(nseg);

	bool collision = window_.declare(hash, nseg);
	if (collision)
		DEBUG(log_) << "Collision in encoder window; cleared old entry.";
	if (segp == NULL)
		nseg->unref();

	/*
	 * Skip to the end.
	 */
	input->skip(XCODEC_SEGMENT_LENGTH);

	if (segp != NULL)
		*segp = nseg;
}

void
XCodecEncoder::encode_escape(Buffer *output, Buffer *input, unsigned length)
{
	ASSERT(log_, length != 0);

	do {
		unsigned offset;
		if (!input->find(XCODEC_MAGIC, &offset, length)) {
			output->append(input, length);
			input->skip(length);
			return;
		}

		if (offset != 0) {
			output->append(input, offset);
			length -= offset;
			input->skip(offset);
		}

		output->append(XCODEC_MAGIC);
		output->append(XCODEC_OP_ESCAPE);

		length -= sizeof XCODEC_MAGIC;
		input->skip(sizeof XCODEC_MAGIC);
	} while (length != 0);
}

bool
XCodecEncoder::encode_reference(Buffer *output, Buffer *input, unsigned offset, uint64_t hash, BufferSegment *oseg, std::map<uint64_t, BufferSegment *> *refmap)
{
	uint8_t data[XCODEC_SEGMENT_LENGTH];
	input->copyout(data, offset, sizeof data);

	if (!oseg->equal(data, sizeof data))
		return (false);

	/*
	 * Skip to the end.
	 */
	input->skip(XCODEC_SEGMENT_LENGTH);

	/*
	 * And output a reference.
	 */
	uint8_t b;
	if (window_.present(hash, oseg, &b)) {
		output->append(XCODEC_MAGIC);
		output->append(XCODEC_OP_BACKREF);
		output->append(b);
	} else {
		output->append(XCODEC_MAGIC);
		output->append(XCODEC_OP_REF);
		uint64_t behash = BigEndian::encode(hash);
		output->append(&behash);

		window_.declare(hash, oseg);
	}

	if (refmap != NULL) {
		std::map<uint64_t, BufferSegment *>::const_iterator it;
		it = refmap->find(hash);
		if (it == refmap->end()) {
			oseg->ref();
			refmap->insert(std::map<uint64_t, BufferSegment *>::value_type(hash, oseg));
		}
	}

	return (true);
}

bool
XCodecEncoder::find_reference(Buffer *output, Buffer *input, unsigned offset, uint64_t hash, std::map<uint64_t, BufferSegment *> *refmap)
{
	BufferSegment *oseg = cache_->lookup(hash);
	if (oseg != NULL) {
		/*
		 * This segment already exists.  If it's
		 * identical to this chunk of data, then that's
		 * positively fantastic.
		 */
		if (encode_reference(output, input, offset, hash, oseg, refmap)) {
			oseg->unref();
			return (true);
		}

		/*
		 * This hash isn't usable because it collides
		 * with another, so keep looking for something
		 * viable.
		 *
		 * XXX
		 * If this is the first hash (i.e.
		 * !candidate.set_) then we can adjust the
		 * start of the current window and escape the
		 * first byte right away.  Does that help?
		 */
		oseg->unref();
		DEBUG(log_) << "Collision in first pass.";
		return (false);
	}

	return (false);
}
<commit_msg>Don't add backrefs to the refmap.<commit_after>/*
 * Copyright (c) 2009-2014 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <common/buffer.h>
#include <common/endian.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_cache.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_hash.h>

struct candidate_symbol {
	bool set_;
	unsigned offset_;
	uint64_t symbol_;
};

XCodecEncoder::XCodecEncoder(XCodecCache *cache)
: log_("/xcodec/encoder"),
  cache_(cache),
  window_(),
  stream_(!cache_->out_of_band())
{ }

XCodecEncoder::~XCodecEncoder()
{ }

/*
 * This takes a view of a data stream and turns it into a series of references
 * to other data, declarations of data to be referenced, and data that needs
 * escaped.
 *
 * The caller may request to retain a map of hashes and segments referenced by
 * this stream, a "refmap".
 *
 * Note that although each refmap is local to the frame referencing it, there
 * is still an issue with how hash reuse within even a single call to this
 * function could occur.  Consider the case of a memory cache limited to 2-3
 * segments.  When a colliding chunk of data is discovered, we will collide
 * within the refmap due to eviction.  The stream's decoding should be
 * decidable, but it is so only if we track an ordered listing of each
 * reference in order and the data it corresponds to and have some way of
 * identifying <ASK>/<LEARN> type requests linearly.  Another solution is
 * needed here, namely to just fail and fail tremendously when we have such
 * a malformed stream of data that we can't guarantee its decoding.  Or we
 * may just want to check the refmap in addition to the backing cache (and
 * maybe in preference to it) to prevent this problem.  But that shifts part
 * of the burden for correct decoding to the decoder, which then has to be
 * more careful about assuming that a <LEARN> covers all of the data it is
 * trying to decode which requests a hash, rather than just one frame.
 */
void
XCodecEncoder::encode(Buffer *output, Buffer *input, std::map<uint64_t, BufferSegment *> *refmap)
{
	if (input->empty())
		return;

	if (input->length() < XCODEC_SEGMENT_LENGTH) {
		encode_escape(output, input, input->length());
		return;
	}

	XCodecHash xcodec_hash;
	candidate_symbol candidate;
	Buffer outq;
	unsigned o = 0;

	candidate.set_ = false;

	/*
	 * While there is input.
	 */
	while (!input->empty()) {
		/*
		 * If we cannot acquire a complete hash within this segment,
		 * stop looking.
		 */
		if (o + input->length() < XCODEC_SEGMENT_LENGTH) {
			input->moveout(&outq);
			break;
		}

		/*
		 * Take the first BufferSegment out of the input Buffer.
		 */
		BufferSegment *seg;
		input->moveout(&seg);

		/*
		 * And add it to a temporary Buffer where input is queued.
		 */
		outq.append(seg);

		/*
		 * And for every byte in this BufferSegment.
		 */
		const uint8_t *p, *q = seg->end();
		for (p = seg->data(); p < q; p++) {
			ptrdiff_t resid = q - p;

			/*
			 * If we cannot acquire a complete hash within this segment.
			 */
			if (o + resid < XCODEC_SEGMENT_LENGTH) {
				/*
				 * Hash all of the bytes from it and continue.
				 */
				o += resid;
				while (p < q)
					xcodec_hash.add(*p++);
				break;
			}

			/*
			 * If we don't have a complete hash.
			 */
			if (o < XCODEC_SEGMENT_LENGTH) {
				for (;;) {
					/*
					 * Add bytes to the hash.
					 */
					xcodec_hash.add(*p);

					/*
					 * Until we have a complete hash.
					 */
					if (++o == XCODEC_SEGMENT_LENGTH)
						break;

					/*
					 * Go to the next byte.
					 */
					p++;
				}
				ASSERT(log_, o == XCODEC_SEGMENT_LENGTH);
			} else {
				/*
				 * Roll it into the rolling hash.
				 */
				xcodec_hash.roll(*p);
				o++;
			}

			ASSERT(log_, o >= XCODEC_SEGMENT_LENGTH);
			ASSERT(log_, p != q);

			/*
			 * And then mix the hash's internal state into a
			 * uint64_t that we can use to refer to that data
			 * and to look up possible past occurances of that
			 * data in the XCodecCache.
			 */
			unsigned start = o - XCODEC_SEGMENT_LENGTH;
			uint64_t hash = xcodec_hash.mix();

			/*
			 * If there is a pending candidate hash that wouldn't
			 * overlap with the data that the rolling hash presently
			 * covers, declare it now.
			 */
			if (candidate.set_ && candidate.offset_ + XCODEC_SEGMENT_LENGTH <= start) {
				BufferSegment *nseg;
				encode_declaration(output, &outq, candidate.offset_, candidate.symbol_, &nseg, refmap);

				o -= candidate.offset_ + XCODEC_SEGMENT_LENGTH;
				start = o - XCODEC_SEGMENT_LENGTH;

				candidate.set_ = false;

				/*
				 * If, on top of that, the just-declared hash is
				 * the same as the current hash, consider referencing
				 * it immediately.
				 */
				if (hash == candidate.symbol_) {
					/*
					 * If it's a hash collision, though, nevermind.
					 * Skip trying to use this hash as a reference,
					 * too, and go on to the next one.
					 */
					if (!encode_reference(output, &outq, start, hash, nseg, refmap)) {
						nseg->unref();
						DEBUG(log_) << "Collision in adjacent-declare pass.";
						continue;
					}
					nseg->unref();

					/*
					 * But if there's no collection, then we can move
					 * on to looking for the *next* hash/data to declare
					 * or reference.
					 */
					o = 0;
					xcodec_hash.reset();

					DEBUG(log_) << "Hit in adjacent-declare pass.";
					continue;
				}
				nseg->unref();
			}

			/*
			 * Now attempt to encode this hash as a reference if it
			 * has been defined before.
			 */
			if (find_reference(output, &outq, start, hash, refmap)) {
				o = 0;
				xcodec_hash.reset();

				/*
				 * We have output any data before this hash
				 * in escaped form, so any candidate hash
				 * before it is invalid now.
				 */
				candidate.set_ = false;
				continue;
			}

			/*
			 * Not defined before, it's a candidate for declaration
			 * if we don't already have one.
			 */
			if (candidate.set_) {
				/*
				 * We already have a hash that occurs earlier,
				 * isn't a collision and includes data that's
				 * covered by this hash, so don't remember it
				 * and keep going.
				 */
				ASSERT(log_, candidate.offset_ + XCODEC_SEGMENT_LENGTH > start);
				continue;
			}

			/*
			 * The hash at this offset doesn't collide with any
			 * other and is the first viable hash we've seen so far
			 * in the stream, so remember it so that if we don't
			 * find something to reference we can declare this one
			 * for future use.
			 */
			candidate.offset_ = start;
			candidate.symbol_ = hash;
			candidate.set_ = true;
		}

		seg->unref();
	}

	/*
	 * Done processing input.  If there's still data in the outq Buffer,
	 * then we need to declare any candidate hashes and escape any data
	 * after them.
	 */

	/*
	 * There's a hash we can declare, do it.
	 */
	if (candidate.set_) {
		ASSERT(log_, !outq.empty());
		encode_declaration(output, &outq, candidate.offset_, candidate.symbol_, NULL, refmap);
		candidate.set_ = false;
	}

	/*
	 * There's data after that hash or no candidate hash, so
	 * just escape it.
	 */
	if (!outq.empty()) {
		encode_escape(output, &outq, outq.length());
	}

	ASSERT(log_, !candidate.set_);
	ASSERT(log_, outq.empty());
	ASSERT(log_, input->empty());
}

void
XCodecEncoder::encode_declaration(Buffer *output, Buffer *input, unsigned offset, uint64_t hash, BufferSegment **segp, std::map<uint64_t, BufferSegment *> *refmap)
{
	if (offset != 0) {
		encode_escape(output, input, offset);
	}

	BufferSegment *nseg;
	input->copyout(&nseg, XCODEC_SEGMENT_LENGTH);

	cache_->enter(hash, nseg);

	if (!stream_) {
		/*
		 * Declarations occur out-of-band.
		 */
		if (!encode_reference(output, input, 0, hash, nseg, refmap)) /* XXX Pass NULL not nseg to skip check?  */
			NOTREACHED(log_);
		if (segp == NULL)
			nseg->unref();
		else
			*segp = nseg;
		return;
	}

	/*
	 * Declarations are extracted in-band.
	 */
	output->append(XCODEC_MAGIC);
	output->append(XCODEC_OP_EXTRACT);
	output->append(nseg);

	bool collision = window_.declare(hash, nseg);
	if (collision)
		DEBUG(log_) << "Collision in encoder window; cleared old entry.";
	if (segp == NULL)
		nseg->unref();

	/*
	 * Skip to the end.
	 */
	input->skip(XCODEC_SEGMENT_LENGTH);

	if (segp != NULL)
		*segp = nseg;
}

void
XCodecEncoder::encode_escape(Buffer *output, Buffer *input, unsigned length)
{
	ASSERT(log_, length != 0);

	do {
		unsigned offset;
		if (!input->find(XCODEC_MAGIC, &offset, length)) {
			output->append(input, length);
			input->skip(length);
			return;
		}

		if (offset != 0) {
			output->append(input, offset);
			length -= offset;
			input->skip(offset);
		}

		output->append(XCODEC_MAGIC);
		output->append(XCODEC_OP_ESCAPE);

		length -= sizeof XCODEC_MAGIC;
		input->skip(sizeof XCODEC_MAGIC);
	} while (length != 0);
}

bool
XCodecEncoder::encode_reference(Buffer *output, Buffer *input, unsigned offset, uint64_t hash, BufferSegment *oseg, std::map<uint64_t, BufferSegment *> *refmap)
{
	uint8_t data[XCODEC_SEGMENT_LENGTH];
	input->copyout(data, offset, sizeof data);

	if (!oseg->equal(data, sizeof data))
		return (false);

	/*
	 * Skip to the end.
	 */
	input->skip(XCODEC_SEGMENT_LENGTH);

	/*
	 * And output a reference.
	 */
	uint8_t b;
	if (window_.present(hash, oseg, &b)) {
		output->append(XCODEC_MAGIC);
		output->append(XCODEC_OP_BACKREF);
		output->append(b);
	} else {
		output->append(XCODEC_MAGIC);
		output->append(XCODEC_OP_REF);
		uint64_t behash = BigEndian::encode(hash);
		output->append(&behash);

		window_.declare(hash, oseg);

		if (refmap != NULL) {
			std::map<uint64_t, BufferSegment *>::const_iterator it;
			it = refmap->find(hash);
			if (it == refmap->end()) {
				oseg->ref();
				refmap->insert(std::map<uint64_t, BufferSegment *>::value_type(hash, oseg));
			}
		}
	}

	return (true);
}

bool
XCodecEncoder::find_reference(Buffer *output, Buffer *input, unsigned offset, uint64_t hash, std::map<uint64_t, BufferSegment *> *refmap)
{
	BufferSegment *oseg = cache_->lookup(hash);
	if (oseg != NULL) {
		/*
		 * This segment already exists.  If it's
		 * identical to this chunk of data, then that's
		 * positively fantastic.
		 */
		if (encode_reference(output, input, offset, hash, oseg, refmap)) {
			oseg->unref();
			return (true);
		}

		/*
		 * This hash isn't usable because it collides
		 * with another, so keep looking for something
		 * viable.
		 *
		 * XXX
		 * If this is the first hash (i.e.
		 * !candidate.set_) then we can adjust the
		 * start of the current window and escape the
		 * first byte right away.  Does that help?
		 */
		oseg->unref();
		DEBUG(log_) << "Collision in first pass.";
		return (false);
	}

	return (false);
}
<|endoftext|>


<commit_before>// Copyright 2010-2011 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>

#include "base/commandlineflags.h"
#include "base/logging.h"
#include "linear_solver/linear_solver.h"
#include "linear_solver/linear_solver.pb.h"

namespace operations_research {
void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
  const double kObjCoef[] = {10.0, 6.0, 4.0};
  const string kVarName[] = {"x1", "x2", "x3"};
  const int numVars = 3;
  const int kNumConstraints = 3;
  const string kConstraintName[] = {"c1", "c2", "c3"};
  const double kConstraintCoef1[] = {1.0, 1.0, 1.0};
  const double kConstraintCoef2[] = {10.0, 4.0, 5.0};
  const double kConstraintCoef3[] = {2.0, 2.0, 6.0};
  const double* kConstraintCoef[] = {kConstraintCoef1,
                                     kConstraintCoef2,
                                     kConstraintCoef3};
  const double kConstraintUb[] = {100.0, 600.0, 300.0};

  MPSolver solver("Max_Example", type);
  const double infinity = solver.infinity();
  MPModelProto model_proto;

  // Create variables and objective function
  for (int j = 0; j < numVars; ++j) {
    MPVariableProto* x = model_proto.add_variables();
    x->set_id(kVarName[j]);
    x->set_lb(0.0);
    x->set_ub(infinity);
    x->set_integer(false);
    MPTermProto* obj_term = model_proto.add_objective_terms();
    obj_term->set_variable_id(kVarName[j]);
    obj_term->set_coefficient(kObjCoef[j]);
  }
  model_proto.set_maximize(true);

  // Create constraints
  for (int i = 0; i < kNumConstraints; ++i) {
    MPConstraintProto* constraint_proto = model_proto.add_constraints();
    constraint_proto->set_id(kConstraintName[i]);
    constraint_proto->set_lb(-infinity);
    constraint_proto->set_ub(kConstraintUb[i]);
    for (int j = 0; j < numVars; ++j) {
      MPTermProto* term = constraint_proto->add_terms();
      term->set_variable_id(kVarName[j]);
      term->set_coefficient(kConstraintCoef[i][j]);
    }
  }

  MPModelRequest model_request;
  model_request.mutable_model()->CopyFrom(model_proto);
  if (type == MPSolver::GLPK_LINEAR_PROGRAMMING) {
    model_request.set_problem_type(MPModelRequest::GLPK_LINEAR_PROGRAMMING);
  } else {
    model_request.set_problem_type(MPModelRequest::CLP_LINEAR_PROGRAMMING);
  }

  MPSolutionResponse solution_response;
  solver.SolveWithProtocolBuffers(model_request, &solution_response);

  // The problem has an optimal solution.
  CHECK_EQ(MPSolver::OPTIMAL, solution_response.result_status());

  LOG(INFO) << "objective = " <<  solution_response.objective_value();
  for (int j = 0; j < numVars; ++j) {
    MPSolutionValue solution_value = solution_response.solution_values(j);
    LOG(INFO) << solution_value.variable_id() << " = "
              << solution_value.value();
  }
}

void RunAllExamples() {
  LOG(INFO) << "----- Running Max Example with GLPK -----";
  BuildLinearProgrammingMaxExample(MPSolver::GLPK_LINEAR_PROGRAMMING);
  LOG(INFO) << "----- Running Max Example with Coin LP -----";
  BuildLinearProgrammingMaxExample(MPSolver::CLP_LINEAR_PROGRAMMING);
}
}  // namespace operations_research

int main(int argc, char **argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  operations_research::RunAllExamples();
  return 0;
}
<commit_msg>fix example<commit_after>// Copyright 2010-2011 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>

#include "base/commandlineflags.h"
#include "base/logging.h"
#include "linear_solver/linear_solver.h"
#include "linear_solver/linear_solver.pb.h"

namespace operations_research {
void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
  const double kObjCoef[] = {10.0, 6.0, 4.0};
  const string kVarName[] = {"x1", "x2", "x3"};
  const int numVars = 3;
  const int kNumConstraints = 3;
  const string kConstraintName[] = {"c1", "c2", "c3"};
  const double kConstraintCoef1[] = {1.0, 1.0, 1.0};
  const double kConstraintCoef2[] = {10.0, 4.0, 5.0};
  const double kConstraintCoef3[] = {2.0, 2.0, 6.0};
  const double* kConstraintCoef[] = {kConstraintCoef1,
                                     kConstraintCoef2,
                                     kConstraintCoef3};
  const double kConstraintUb[] = {100.0, 600.0, 300.0};

  MPSolver solver("Max_Example", type);
  const double infinity = solver.infinity();
  MPModelProto model_proto;

  // Create variables and objective function
  for (int j = 0; j < numVars; ++j) {
    MPVariableProto* x = model_proto.add_variables();
    x->set_id(kVarName[j]);
    x->set_lb(0.0);
    x->set_ub(infinity);
    x->set_integer(false);
    MPTermProto* obj_term = model_proto.add_objective_terms();
    obj_term->set_variable_id(kVarName[j]);
    obj_term->set_coefficient(kObjCoef[j]);
  }
  model_proto.set_maximize(true);

  // Create constraints
  for (int i = 0; i < kNumConstraints; ++i) {
    MPConstraintProto* constraint_proto = model_proto.add_constraints();
    constraint_proto->set_id(kConstraintName[i]);
    constraint_proto->set_lb(-infinity);
    constraint_proto->set_ub(kConstraintUb[i]);
    for (int j = 0; j < numVars; ++j) {
      MPTermProto* term = constraint_proto->add_terms();
      term->set_variable_id(kVarName[j]);
      term->set_coefficient(kConstraintCoef[i][j]);
    }
  }

  MPModelRequest model_request;
  model_request.mutable_model()->CopyFrom(model_proto);
  if (type == MPSolver::GLPK_LINEAR_PROGRAMMING) {
    model_request.set_problem_type(MPModelRequest::GLPK_LINEAR_PROGRAMMING);
  } else {
    model_request.set_problem_type(MPModelRequest::CLP_LINEAR_PROGRAMMING);
  }

  MPSolutionResponse solution_response;
  solver.SolveWithProtocolBuffers(model_request, &solution_response);

  // The problem has an optimal solution.
  CHECK_EQ(MPSolver::OPTIMAL, solution_response.result_status());

  LOG(INFO) << "objective = " <<  solution_response.objective_value();
  const int num_non_zeros = solution_response.solution_values_size();
  for (int j = 0; j < num_non_zeros; ++j) {
    MPSolutionValue solution_value = solution_response.solution_values(j);
    LOG(INFO) << solution_value.variable_id() << " = "
              << solution_value.value();
  }
}

void RunAllExamples() {
  LOG(INFO) << "----- Running Max Example with GLPK -----";
  BuildLinearProgrammingMaxExample(MPSolver::GLPK_LINEAR_PROGRAMMING);
  LOG(INFO) << "----- Running Max Example with Coin LP -----";
  BuildLinearProgrammingMaxExample(MPSolver::CLP_LINEAR_PROGRAMMING);
}
}  // namespace operations_research

int main(int argc, char **argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  operations_research::RunAllExamples();
  return 0;
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include "TransferFunctionWidget.h"

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/TexGen>
#include <osg/AlphaFunc>
#include <osg/Texture2D>
#include <osg/MatrixTransform>
#include <osg/io_utils>

#include <osgGA/EventVisitor>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/View>

using namespace osgUI;

TransferFunctionWidget::TransferFunctionWidget(osg::TransferFunction1D* tf):
    _min(FLT_MAX),
    _max(-FLT_MAX),
    _left(FLT_MAX),
    _right(-FLT_MAX),
    _startedDrag(false),
    _previousDragPosition(0.0f)
{
    setNumChildrenRequiringEventTraversal(1);
    setExtents(osg::BoundingBox(0.0,0.0,0.0,1.0,1.0,0.0));
    setTransferFunction(tf);
}

TransferFunctionWidget::TransferFunctionWidget(const TransferFunctionWidget& tfw, const osg::CopyOp& copyop):
    Widget(tfw,copyop)
{
    setExtents(tfw.getExtents());
    setTransferFunction(tfw.getTransferFunction());
}

void TransferFunctionWidget::setTransferFunction(const osg::TransferFunction1D* tf)
{
    if (_transferFunction==tf) return;

    _transferFunction = const_cast<osg::TransferFunction1D*>(tf);

    if (_transferFunction.valid())
    {
        osg::TransferFunction1D::ColorMap& colorMap = _transferFunction->getColorMap();
        if (colorMap.empty())
        {
            _min = FLT_MAX;
            _max = -FLT_MAX;
        }
        else
        {
            _min = colorMap.begin()->first;
            _max = colorMap.rbegin()->first;
        }
    }

    resetVisibleRange();
}

void TransferFunctionWidget::resetVisibleRange()
{
    setVisibleRange(_min, _max);
}

void TransferFunctionWidget::setVisibleRange(float left, float right)
{
    if (left<_min) left = _min;
    if (right>_max) right = _max;

    _left = left;
    _right = right;
//    OSG_NOTICE<<"setVisibleRange("<<_left<<", "<<_right<<")"<<std::endl;
    createGraphics();
}

void TransferFunctionWidget::translateVisibleRange(float delta)
{
    float new_left = _left+(_right-_left)*delta;
    float new_right = _right+(_right-_left)*delta;
    if (delta<0.0)
    {
        if (new_left<_min)
        {
            new_right += (_min-new_left);
            new_left = _min;
        }
    }
    else
    {
        if (new_right>_max)
        {
            new_left += (_max-new_right);
            new_right = _max;
        }
    }

    setVisibleRange(new_left, new_right);
}

void TransferFunctionWidget::scaleVisibleRange(float center, float delta)
{
    float scale = powf(2.0, delta);
    setVisibleRange(center+(_left-center)*scale,
                    center+(_right-center)*scale);
}

void TransferFunctionWidget::traverse(osg::NodeVisitor& nv)
{
    Widget::traverse(nv);
}

bool TransferFunctionWidget::handle(osgGA::EventVisitor* ev, osgGA::Event* event)
{
    osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
    if (!ea) return false;

    switch(ea->getEventType())
    {
        case(osgGA::GUIEventAdapter::PUSH):
            // OSG_NOTICE<<"Pressed button "<<ea->getButton()<<std::endl;
            _startedDrag = false;
            if (ea->getButtonMask()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
            {
                osg::Vec3 position;
                if (computePositionInLocalCoordinates(ev, ea, position))
                {
                    _startedDrag = true;
                    _previousDragPosition = position.x();
                }
            }
            break;
        case(osgGA::GUIEventAdapter::RELEASE):
            // OSG_NOTICE<<"Released button "<<ea->getButton()<<std::endl;
            _startedDrag = false;
            break;
        case(osgGA::GUIEventAdapter::DRAG):
            // OSG_NOTICE<<"Dragged "<<std::endl;
            if (_startedDrag)
            {
                osg::Vec3 position;
                if (computePositionInLocalCoordinates(ev, ea, position))
                {
                    float delta = -(position.x()-_previousDragPosition);

                    _previousDragPosition = position.x();

                    translateVisibleRange(delta);
                }
            }
            break;
        case(osgGA::GUIEventAdapter::SCROLL):
        {
            osg::Vec3 position;
            if (computePositionInLocalCoordinates(ev, ea, position))
            {
                float translation = 0.0;
                float increment = 0.1;
                float scale = 1.0;
                float ratio = (1.0f+increment);
                switch(ea->getScrollingMotion())
                {
                    case(osgGA::GUIEventAdapter::SCROLL_NONE):
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_LEFT):
                        translation -= increment;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_RIGHT):
                        translation += increment;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_UP):
                        scale /= ratio;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_DOWN):
                        scale *= ratio;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_2D):
                        translation = increment*ea->getScrollingDeltaX();
                        scale = powf(ratio, increment*ea->getScrollingDeltaY());
                        break;
                }
                float center = _left+(_right-_left)*position.x();
                // OSG_NOTICE<<"translation = "<<translation<<", scale = "<<scale<<", x="<<position.x()<<", center="<<center<<std::endl;
                setVisibleRange(translation+center+(_left-center)*scale,
                                translation+center+(_right-center)*scale);

            }
            break;
        }
        case(osgGA::GUIEventAdapter::KEYDOWN):
        {
            // OSG_NOTICE<<"Pressed key"<<ea->getKey()<<std::endl;
            float delta = 0.02;
            if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Left) translateVisibleRange(-delta);
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Right) translateVisibleRange(delta);
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Up) scaleVisibleRange((_left+_right)*0.5f, -delta);
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down) scaleVisibleRange((_left+_right)*0.5f, delta);
            break;
        }
        case(osgGA::GUIEventAdapter::KEYUP):
            // OSG_NOTICE<<"Released key"<<ea->getKey()<<std::endl;
            if (ea->getKey()==' ' ||ea->getKey()==osgGA::GUIEventAdapter::KEY_Home) resetVisibleRange();
            break;
        default:
            break;
    }
    return false;
}

void TransferFunctionWidget::createGraphics()
{
//    OSG_NOTICE<<"Create graphics"<<std::endl;

    typedef osg::TransferFunction1D::ColorMap ColorMap;
    ColorMap& colorMap = _transferFunction->getColorMap();
    if (colorMap.empty()) return;

    float depth = 0.0f;
    float yMax = 0.0f;

    // find yMax
    for(ColorMap::iterator itr = colorMap.begin();
        itr != colorMap.end();
        ++itr)
    {
        float y = itr->second[3];
        if (y>yMax) yMax = y;
    }

    float xScale = 1.0f/(_right-_left);
    float xOffset = -_left;
    float yScale = 1.0f/yMax;

    if (!_geode)
    {
        _geode = new osg::Geode;
        addChild(_geode.get());
    }

    {

        if (!_geometry)
        {
            _geometry = new osg::Geometry;
            _geometry->setDataVariance(osg::Geometry::DYNAMIC);
            _geometry->setUseDisplayList(false);
            _geometry->setUseVertexBufferObjects(false);

            _geode->addDrawable(_geometry.get());

            osg::ref_ptr<osg::StateSet> stateset = _geometry->getOrCreateStateSet();

            stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
            stateset->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);

            osg::ref_ptr<osg::AlphaFunc> alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f);
            stateset->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);

            osg::ref_ptr<osg::Image> image = new osg::Image;
            image->allocateImage(1,1,1, GL_RGBA, GL_UNSIGNED_BYTE);
            unsigned char* data = image->data();
            data[0] = 255;
            data[1] = 255;
            data[2] = 255;
            data[3] = 255;

            osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
            texture->setImage(image.get());
            texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
            texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_BORDER);
            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_BORDER);
            texture->setBorderColor(osg::Vec4(1.0f,1.0f,0.0f,0.0f));

            stateset->setTextureAttribute(0, texture.get());

            osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
            texgen->setMode(osg::TexGen::OBJECT_LINEAR);
            texgen->setPlane(osg::TexGen::S, osg::Plane(1.0,0.0,0.0,0.0));
            texgen->setPlane(osg::TexGen::T, osg::Plane(0.0,1.0,0.0,0.0));

            stateset->setTextureAttribute(0, texgen.get());
            stateset->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
            stateset->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
            stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
        }

        if (!_vertices)
        {
            _vertices = new osg::Vec3Array;
            _geometry->setVertexArray(_vertices.get());
        }

        if (!_colours)
        {
            _colours = new osg::Vec4Array;
            _geometry->setColorArray(_colours.get(), osg::Array::BIND_PER_VERTEX);
        }

        osg::Vec4 background_color(1.0f, 1.0f, 1.0f, 0.1f);

        unsigned numColumnsRequired = colorMap.size();
        _vertices->resize(0);
        _vertices->reserve(numColumnsRequired*3);
        for(ColorMap::iterator itr = colorMap.begin();
            itr != colorMap.end();
            ++itr)
        {
            float x = itr->first;
            osg::Vec4 color = itr->second;

            float y = itr->second[3];
            color[3] = 1.0f;

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, 0.0f, depth));
            _colours->push_back(color);

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth));
            _colours->push_back(color);

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth));
            _colours->push_back(background_color);

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, yMax*yScale, depth));
            _colours->push_back(background_color);
        }

        if (!_background_primitives)
        {
            _background_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
            _geometry->addPrimitiveSet(_background_primitives.get());
        }

        if (!_historgram_primitives)
        {
            _historgram_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
            _geometry->addPrimitiveSet(_historgram_primitives.get());
        }

        if (!_outline_primitives)
        {
            _outline_primitives = new osg::DrawElementsUShort(GL_LINE_STRIP);
            _geometry->addPrimitiveSet(_outline_primitives.get());
        }

        _background_primitives->resize(0);
        _historgram_primitives->resize(0);
        _outline_primitives->resize(0);

        for(unsigned int i=0; i<numColumnsRequired; ++i)
        {
            int iv = i*4;

            _background_primitives->push_back(iv+3);
            _background_primitives->push_back(iv+2);

            _historgram_primitives->push_back(iv+1);
            _historgram_primitives->push_back(iv+0);

            _outline_primitives->push_back(iv+1);
        }

    }

#if 0
    static bool first = true;
    if (first)
    {
        osgDB::writeNodeFile(*_geode, "test.osgt");
        first = false;
    }
#endif

    _geometry->dirtyBound();

    // make sure the general widget geometry/state is created and _graphicsInitialized reset to false
    Widget::createGraphics();
}
<commit_msg>Build fixes for when ref_ptr<> automatic type conversion is turned off<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include "TransferFunctionWidget.h"

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/TexGen>
#include <osg/AlphaFunc>
#include <osg/Texture2D>
#include <osg/MatrixTransform>
#include <osg/io_utils>

#include <osgGA/EventVisitor>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/View>

using namespace osgUI;

TransferFunctionWidget::TransferFunctionWidget(osg::TransferFunction1D* tf):
    _min(FLT_MAX),
    _max(-FLT_MAX),
    _left(FLT_MAX),
    _right(-FLT_MAX),
    _startedDrag(false),
    _previousDragPosition(0.0f)
{
    setNumChildrenRequiringEventTraversal(1);
    setExtents(osg::BoundingBox(0.0,0.0,0.0,1.0,1.0,0.0));
    setTransferFunction(tf);
}

TransferFunctionWidget::TransferFunctionWidget(const TransferFunctionWidget& tfw, const osg::CopyOp& copyop):
    Widget(tfw,copyop)
{
    setExtents(tfw.getExtents());
    setTransferFunction(tfw.getTransferFunction());
}

void TransferFunctionWidget::setTransferFunction(const osg::TransferFunction1D* tf)
{
    if (_transferFunction==tf) return;

    _transferFunction = const_cast<osg::TransferFunction1D*>(tf);

    if (_transferFunction.valid())
    {
        osg::TransferFunction1D::ColorMap& colorMap = _transferFunction->getColorMap();
        if (colorMap.empty())
        {
            _min = FLT_MAX;
            _max = -FLT_MAX;
        }
        else
        {
            _min = colorMap.begin()->first;
            _max = colorMap.rbegin()->first;
        }
    }

    resetVisibleRange();
}

void TransferFunctionWidget::resetVisibleRange()
{
    setVisibleRange(_min, _max);
}

void TransferFunctionWidget::setVisibleRange(float left, float right)
{
    if (left<_min) left = _min;
    if (right>_max) right = _max;

    _left = left;
    _right = right;
//    OSG_NOTICE<<"setVisibleRange("<<_left<<", "<<_right<<")"<<std::endl;
    createGraphics();
}

void TransferFunctionWidget::translateVisibleRange(float delta)
{
    float new_left = _left+(_right-_left)*delta;
    float new_right = _right+(_right-_left)*delta;
    if (delta<0.0)
    {
        if (new_left<_min)
        {
            new_right += (_min-new_left);
            new_left = _min;
        }
    }
    else
    {
        if (new_right>_max)
        {
            new_left += (_max-new_right);
            new_right = _max;
        }
    }

    setVisibleRange(new_left, new_right);
}

void TransferFunctionWidget::scaleVisibleRange(float center, float delta)
{
    float scale = powf(2.0, delta);
    setVisibleRange(center+(_left-center)*scale,
                    center+(_right-center)*scale);
}

void TransferFunctionWidget::traverse(osg::NodeVisitor& nv)
{
    Widget::traverse(nv);
}

bool TransferFunctionWidget::handle(osgGA::EventVisitor* ev, osgGA::Event* event)
{
    osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
    if (!ea) return false;

    switch(ea->getEventType())
    {
        case(osgGA::GUIEventAdapter::PUSH):
            // OSG_NOTICE<<"Pressed button "<<ea->getButton()<<std::endl;
            _startedDrag = false;
            if (ea->getButtonMask()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
            {
                osg::Vec3 position;
                if (computePositionInLocalCoordinates(ev, ea, position))
                {
                    _startedDrag = true;
                    _previousDragPosition = position.x();
                }
            }
            break;
        case(osgGA::GUIEventAdapter::RELEASE):
            // OSG_NOTICE<<"Released button "<<ea->getButton()<<std::endl;
            _startedDrag = false;
            break;
        case(osgGA::GUIEventAdapter::DRAG):
            // OSG_NOTICE<<"Dragged "<<std::endl;
            if (_startedDrag)
            {
                osg::Vec3 position;
                if (computePositionInLocalCoordinates(ev, ea, position))
                {
                    float delta = -(position.x()-_previousDragPosition);

                    _previousDragPosition = position.x();

                    translateVisibleRange(delta);
                }
            }
            break;
        case(osgGA::GUIEventAdapter::SCROLL):
        {
            osg::Vec3 position;
            if (computePositionInLocalCoordinates(ev, ea, position))
            {
                float translation = 0.0;
                float increment = 0.1;
                float scale = 1.0;
                float ratio = (1.0f+increment);
                switch(ea->getScrollingMotion())
                {
                    case(osgGA::GUIEventAdapter::SCROLL_NONE):
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_LEFT):
                        translation -= increment;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_RIGHT):
                        translation += increment;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_UP):
                        scale /= ratio;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_DOWN):
                        scale *= ratio;
                        break;
                    case(osgGA::GUIEventAdapter::SCROLL_2D):
                        translation = increment*ea->getScrollingDeltaX();
                        scale = powf(ratio, increment*ea->getScrollingDeltaY());
                        break;
                }
                float center = _left+(_right-_left)*position.x();
                // OSG_NOTICE<<"translation = "<<translation<<", scale = "<<scale<<", x="<<position.x()<<", center="<<center<<std::endl;
                setVisibleRange(translation+center+(_left-center)*scale,
                                translation+center+(_right-center)*scale);

            }
            break;
        }
        case(osgGA::GUIEventAdapter::KEYDOWN):
        {
            // OSG_NOTICE<<"Pressed key"<<ea->getKey()<<std::endl;
            float delta = 0.02;
            if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Left) translateVisibleRange(-delta);
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Right) translateVisibleRange(delta);
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Up) scaleVisibleRange((_left+_right)*0.5f, -delta);
            else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down) scaleVisibleRange((_left+_right)*0.5f, delta);
            break;
        }
        case(osgGA::GUIEventAdapter::KEYUP):
            // OSG_NOTICE<<"Released key"<<ea->getKey()<<std::endl;
            if (ea->getKey()==' ' ||ea->getKey()==osgGA::GUIEventAdapter::KEY_Home) resetVisibleRange();
            break;
        default:
            break;
    }
    return false;
}

void TransferFunctionWidget::createGraphics()
{
//    OSG_NOTICE<<"Create graphics"<<std::endl;

    typedef osg::TransferFunction1D::ColorMap ColorMap;
    ColorMap& colorMap = _transferFunction->getColorMap();
    if (colorMap.empty()) return;

    float depth = 0.0f;
    float yMax = 0.0f;

    // find yMax
    for(ColorMap::iterator itr = colorMap.begin();
        itr != colorMap.end();
        ++itr)
    {
        float y = itr->second[3];
        if (y>yMax) yMax = y;
    }

    float xScale = 1.0f/(_right-_left);
    float xOffset = -_left;
    float yScale = 1.0f/yMax;

    if (!_geode)
    {
        _geode = new osg::Geode;
        addChild(_geode.get());
    }

    {

        if (!_geometry)
        {
            _geometry = new osg::Geometry;
            _geometry->setDataVariance(osg::Geometry::DYNAMIC);
            _geometry->setUseDisplayList(false);
            _geometry->setUseVertexBufferObjects(false);

            _geode->addDrawable(_geometry.get());

            osg::ref_ptr<osg::StateSet> stateset = _geometry->getOrCreateStateSet();

            stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
            stateset->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);

            osg::ref_ptr<osg::AlphaFunc> alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f);
            stateset->setAttributeAndModes(alphaFunc.get(), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);

            osg::ref_ptr<osg::Image> image = new osg::Image;
            image->allocateImage(1,1,1, GL_RGBA, GL_UNSIGNED_BYTE);
            unsigned char* data = image->data();
            data[0] = 255;
            data[1] = 255;
            data[2] = 255;
            data[3] = 255;

            osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
            texture->setImage(image.get());
            texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
            texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_BORDER);
            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_BORDER);
            texture->setBorderColor(osg::Vec4(1.0f,1.0f,0.0f,0.0f));

            stateset->setTextureAttribute(0, texture.get());

            osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
            texgen->setMode(osg::TexGen::OBJECT_LINEAR);
            texgen->setPlane(osg::TexGen::S, osg::Plane(1.0,0.0,0.0,0.0));
            texgen->setPlane(osg::TexGen::T, osg::Plane(0.0,1.0,0.0,0.0));

            stateset->setTextureAttribute(0, texgen.get());
            stateset->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
            stateset->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
            stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
        }

        if (!_vertices)
        {
            _vertices = new osg::Vec3Array;
            _geometry->setVertexArray(_vertices.get());
        }

        if (!_colours)
        {
            _colours = new osg::Vec4Array;
            _geometry->setColorArray(_colours.get(), osg::Array::BIND_PER_VERTEX);
        }

        osg::Vec4 background_color(1.0f, 1.0f, 1.0f, 0.1f);

        unsigned numColumnsRequired = colorMap.size();
        _vertices->resize(0);
        _vertices->reserve(numColumnsRequired*3);
        for(ColorMap::iterator itr = colorMap.begin();
            itr != colorMap.end();
            ++itr)
        {
            float x = itr->first;
            osg::Vec4 color = itr->second;

            float y = itr->second[3];
            color[3] = 1.0f;

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, 0.0f, depth));
            _colours->push_back(color);

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth));
            _colours->push_back(color);

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth));
            _colours->push_back(background_color);

            _vertices->push_back(osg::Vec3((x+xOffset)*xScale, yMax*yScale, depth));
            _colours->push_back(background_color);
        }

        if (!_background_primitives)
        {
            _background_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
            _geometry->addPrimitiveSet(_background_primitives.get());
        }

        if (!_historgram_primitives)
        {
            _historgram_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
            _geometry->addPrimitiveSet(_historgram_primitives.get());
        }

        if (!_outline_primitives)
        {
            _outline_primitives = new osg::DrawElementsUShort(GL_LINE_STRIP);
            _geometry->addPrimitiveSet(_outline_primitives.get());
        }

        _background_primitives->resize(0);
        _historgram_primitives->resize(0);
        _outline_primitives->resize(0);

        for(unsigned int i=0; i<numColumnsRequired; ++i)
        {
            int iv = i*4;

            _background_primitives->push_back(iv+3);
            _background_primitives->push_back(iv+2);

            _historgram_primitives->push_back(iv+1);
            _historgram_primitives->push_back(iv+0);

            _outline_primitives->push_back(iv+1);
        }

    }

#if 0
    static bool first = true;
    if (first)
    {
        osgDB::writeNodeFile(*_geode, "test.osgt");
        first = false;
    }
#endif

    _geometry->dirtyBound();

    // make sure the general widget geometry/state is created and _graphicsInitialized reset to false
    Widget::createGraphics();
}
<|endoftext|>