<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef SRS_KERNEL_LOG_HPP
#define SRS_KERNEL_LOG_HPP

/*
#include <srs_kernel_log.hpp>
*/

#include <srs_core.hpp>

#include <stdio.h>

#include <errno.h>
#include <string.h>

#include <srs_kernel_consts.hpp>

/**
* the log level, for example:
* if specified Debug level, all level messages will be logged.
* if specified Warn level, only Warn/Error/Fatal level messages will be logged.
*/
class SrsLogLevel
{
public:
    // only used for very verbose debug, generally,
    // we compile without this level for high performance.
    static const int Verbose = 0x01;
    static const int Info = 0x02;
    static const int Trace = 0x03;
    static const int Warn = 0x04;
    static const int Error = 0x05;
};

/**
* the log interface provides method to write log.
* but we provides some macro, which enable us to disable the log when compile.
* @see also SmtDebug/SmtTrace/SmtWarn/SmtError which is corresponding to Debug/Trace/Warn/Fatal.
*/
class ISrsLog
{
public:
    ISrsLog();
    virtual ~ISrsLog();
public:
    /**
    * initialize log utilities.
    */
    virtual int initialize();
public:
    /**
    * log for verbose, very verbose information.
    */
    virtual void verbose(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for debug, detail information.
    */
    virtual void info(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for trace, important information.
    */
    virtual void trace(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for warn, warn is something should take attention, but not a error.
    */
    virtual void warn(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for error, something error occur, do something about the error, ie. close the connection,
    * but we will donot abort the program.
    */
    virtual void error(const char* tag, int context_id, const char* fmt, ...);
};

// the context for multiple clients.
class ISrsThreadContext
{
public:
    ISrsThreadContext();
    virtual ~ISrsThreadContext();
public:
    virtual void generate_id();
    virtual int get_id();
};

// user must provides a log object
extern ISrsLog* _srs_log;

// user must implements the LogContext and define a global instance.
extern ISrsThreadContext* _srs_context;

// donot print method
#if 1
    #define srs_verbose(msg, ...) _srs_log->verbose(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_info(msg, ...)    _srs_log->info(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_trace(msg, ...)   _srs_log->trace(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_warn(msg, ...)    _srs_log->warn(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_error(msg, ...)   _srs_log->error(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
// use __FUNCTION__ to print c method
#elif 0
    #define srs_verbose(msg, ...) _srs_log->verbose(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_info(msg, ...)    _srs_log->info(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_trace(msg, ...)   _srs_log->trace(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_warn(msg, ...)    _srs_log->warn(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_error(msg, ...)   _srs_log->error(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
// use __PRETTY_FUNCTION__ to print c++ class:method
#else
    #define srs_verbose(msg, ...) _srs_log->verbose(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_info(msg, ...)    _srs_log->info(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_trace(msg, ...)   _srs_log->trace(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_warn(msg, ...)    _srs_log->warn(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_error(msg, ...)   _srs_log->error(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
#endif

#if 0
    #undef srs_verbose
    #define srs_verbose(msg, ...) (void)0
#endif
#if 0
    #undef srs_info
    #define srs_info(msg, ...) (void)0
#endif
#if 0
    #undef srs_trace
    #define srs_trace(msg, ...) (void)0
#endif

#endif
<commit_msg>add todo fixme for log verbose and info<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef SRS_KERNEL_LOG_HPP
#define SRS_KERNEL_LOG_HPP

/*
#include <srs_kernel_log.hpp>
*/

#include <srs_core.hpp>

#include <stdio.h>

#include <errno.h>
#include <string.h>

#include <srs_kernel_consts.hpp>

/**
* the log level, for example:
* if specified Debug level, all level messages will be logged.
* if specified Warn level, only Warn/Error/Fatal level messages will be logged.
*/
class SrsLogLevel
{
public:
    // only used for very verbose debug, generally,
    // we compile without this level for high performance.
    static const int Verbose = 0x01;
    static const int Info = 0x02;
    static const int Trace = 0x03;
    static const int Warn = 0x04;
    static const int Error = 0x05;
};

/**
* the log interface provides method to write log.
* but we provides some macro, which enable us to disable the log when compile.
* @see also SmtDebug/SmtTrace/SmtWarn/SmtError which is corresponding to Debug/Trace/Warn/Fatal.
*/
class ISrsLog
{
public:
    ISrsLog();
    virtual ~ISrsLog();
public:
    /**
    * initialize log utilities.
    */
    virtual int initialize();
public:
    /**
    * log for verbose, very verbose information.
    */
    virtual void verbose(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for debug, detail information.
    */
    virtual void info(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for trace, important information.
    */
    virtual void trace(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for warn, warn is something should take attention, but not a error.
    */
    virtual void warn(const char* tag, int context_id, const char* fmt, ...);
    /**
    * log for error, something error occur, do something about the error, ie. close the connection,
    * but we will donot abort the program.
    */
    virtual void error(const char* tag, int context_id, const char* fmt, ...);
};

// the context for multiple clients.
class ISrsThreadContext
{
public:
    ISrsThreadContext();
    virtual ~ISrsThreadContext();
public:
    virtual void generate_id();
    virtual int get_id();
};

// user must provides a log object
extern ISrsLog* _srs_log;

// user must implements the LogContext and define a global instance.
extern ISrsThreadContext* _srs_context;

// donot print method
#if 1
    #define srs_verbose(msg, ...) _srs_log->verbose(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_info(msg, ...)    _srs_log->info(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_trace(msg, ...)   _srs_log->trace(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_warn(msg, ...)    _srs_log->warn(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_error(msg, ...)   _srs_log->error(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
// use __FUNCTION__ to print c method
#elif 0
    #define srs_verbose(msg, ...) _srs_log->verbose(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_info(msg, ...)    _srs_log->info(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_trace(msg, ...)   _srs_log->trace(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_warn(msg, ...)    _srs_log->warn(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_error(msg, ...)   _srs_log->error(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
// use __PRETTY_FUNCTION__ to print c++ class:method
#else
    #define srs_verbose(msg, ...) _srs_log->verbose(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_info(msg, ...)    _srs_log->info(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_trace(msg, ...)   _srs_log->trace(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_warn(msg, ...)    _srs_log->warn(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
    #define srs_error(msg, ...)   _srs_log->error(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
#endif

// TODO: FIXME: add more verbose and info logs.
#if 1
    #undef srs_verbose
    #define srs_verbose(msg, ...) (void)0
#endif
#if 1
    #undef srs_info
    #define srs_info(msg, ...) (void)0
#endif
#if 0
    #undef srs_trace
    #define srs_trace(msg, ...) (void)0
#endif

#endif
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(simple-rtmp-server)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <srs_app_statistic.hpp>

#include <unistd.h>
#include <sstream>
using namespace std;

#include <srs_rtmp_stack.hpp>
#include <srs_app_json.hpp>
#include <srs_protocol_kbps.hpp>
#include <srs_app_conn.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp>

int64_t srs_gvid = getpid();

int64_t srs_generate_id()
{
    return srs_gvid++;
}

SrsStatisticVhost::SrsStatisticVhost()
{
    id = srs_generate_id();

    kbps = new SrsKbps();
    kbps->set_io(NULL, NULL);
}

SrsStatisticVhost::~SrsStatisticVhost()
{
    srs_freep(kbps);
}

SrsStatisticStream::SrsStatisticStream()
{
    id = srs_generate_id();
    vhost = NULL;
    status = STATISTIC_STREAM_STATUS_IDLING;

    has_video = false;
    vcodec = SrsCodecVideoReserved;
    avc_profile = SrsAvcProfileReserved;
    avc_level = SrsAvcLevelReserved;

    has_audio = false;
    acodec = SrsCodecAudioReserved1;
    asample_rate = SrsCodecAudioSampleRateReserved;
    asound_type = SrsCodecAudioSoundTypeReserved;
    aac_object = SrsAacObjectTypeReserved;

    kbps = new SrsKbps();
    kbps->set_io(NULL, NULL);
}

SrsStatisticStream::~SrsStatisticStream()
{
    srs_freep(kbps);
}

void SrsStatisticStream::publish()
{
    status = STATISTIC_STREAM_STATUS_PUBLISHING;
}

void SrsStatisticStream::close()
{
    has_video = false;
    has_audio = false;
    status = STATISTIC_STREAM_STATUS_IDLING;
}

SrsStatistic* SrsStatistic::_instance = new SrsStatistic();

SrsStatistic::SrsStatistic()
{
    _server_id = srs_generate_id();

    kbps = new SrsKbps();
    kbps->set_io(NULL, NULL);
}

SrsStatistic::~SrsStatistic()
{
    srs_freep(kbps);

    if (true) {
        std::map<std::string, SrsStatisticVhost*>::iterator it;
        for (it = vhosts.begin(); it != vhosts.end(); it++) {
            SrsStatisticVhost* vhost = it->second;
            srs_freep(vhost);
        }
    }
    if (true) {
        std::map<std::string, SrsStatisticStream*>::iterator it;
        for (it = streams.begin(); it != streams.end(); it++) {
            SrsStatisticStream* stream = it->second;
            srs_freep(stream);
        }
    }
    if (true) {
        std::map<int, SrsStatisticClient*>::iterator it;
        for (it = clients.begin(); it != clients.end(); it++) {
            SrsStatisticClient* client = it->second;
            srs_freep(client);
        }
    }
}

SrsStatistic* SrsStatistic::instance()
{
    return _instance;
}

SrsStatisticStream* SrsStatistic::find_stream(int stream_id)
{
    std::map<int, SrsStatisticClient*>::iterator it;
    for (it = clients.begin(); it != clients.end(); it++) {
        SrsStatisticClient* client = it->second;
        SrsStatisticStream* stream = client->stream;

        if (stream_id == stream->id) {
            return stream;
        }
    }
    return NULL;
}

int SrsStatistic::on_video_info(SrsRequest* req,
    SrsCodecVideo vcodec, SrsAvcProfile avc_profile, SrsAvcLevel avc_level
) {
    int ret = ERROR_SUCCESS;

    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->has_video = true;
    stream->vcodec = vcodec;
    stream->avc_profile = avc_profile;
    stream->avc_level = avc_level;

    return ret;
}

int SrsStatistic::on_audio_info(SrsRequest* req,
    SrsCodecAudio acodec, SrsCodecAudioSampleRate asample_rate, SrsCodecAudioSoundType asound_type,
    SrsAacObjectType aac_object
) {
    int ret = ERROR_SUCCESS;

    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->has_audio = true;
    stream->acodec = acodec;
    stream->asample_rate = asample_rate;
    stream->asound_type = asound_type;
    stream->aac_object = aac_object;

    return ret;
}

void SrsStatistic::on_stream_publish(SrsRequest* req)
{
    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->publish();
}

void SrsStatistic::on_stream_close(SrsRequest* req)
{
    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->close();
}

int SrsStatistic::on_client(int id, SrsRequest* req)
{
    int ret = ERROR_SUCCESS;

    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    // create client if not exists
    SrsStatisticClient* client = NULL;
    if (clients.find(id) == clients.end()) {
        client = new SrsStatisticClient();
        client->id = id;
        client->stream = stream;
        clients[id] = client;
    } else {
        client = clients[id];
    }

    return ret;
}

void SrsStatistic::on_disconnect(int id)
{
    std::map<int, SrsStatisticClient*>::iterator it;
    it = clients.find(id);
    if (it != clients.end()) {
        SrsStatisticClient* client = it->second;
        srs_freep(client);
        clients.erase(it);
    }
}

void SrsStatistic::kbps_add_delta(SrsConnection* conn)
{
    int id = conn->srs_id();
    if (clients.find(id) == clients.end()) {
        return;
    }

    SrsStatisticClient* client = clients[id];

    // resample the kbps to collect the delta.
    conn->resample();

    // add delta of connection to kbps.
    // for next sample() of server kbps can get the stat.
    kbps->add_delta(conn);
    client->stream->kbps->add_delta(conn);
    client->stream->vhost->kbps->add_delta(conn);

    // cleanup the delta.
    conn->cleanup();
}

SrsKbps* SrsStatistic::kbps_sample()
{
    kbps->sample();
    if (true) {
        std::map<std::string, SrsStatisticVhost*>::iterator it;
        for (it = vhosts.begin(); it != vhosts.end(); it++) {
            SrsStatisticVhost* vhost = it->second;
            vhost->kbps->sample();
        }
    }
    if (true) {
        std::map<std::string, SrsStatisticStream*>::iterator it;
        for (it = streams.begin(); it != streams.end(); it++) {
            SrsStatisticStream* stream = it->second;
            stream->kbps->sample();
        }
    }

    return kbps;
}

int64_t SrsStatistic::server_id()
{
    return _server_id;
}

int SrsStatistic::dumps_vhosts(stringstream& ss)
{
    int ret = ERROR_SUCCESS;

    ss << SRS_JARRAY_START;
    std::map<std::string, SrsStatisticVhost*>::iterator it;
    for (it = vhosts.begin(); it != vhosts.end(); it++) {
        SrsStatisticVhost* vhost = it->second;
        if (it != vhosts.begin()) {
            ss << SRS_JFIELD_CONT;
        }

        // dumps the config of vhost.
        bool hls_enabled = _srs_config->get_hls_enabled(vhost->vhost);

        ss << SRS_JOBJECT_START
                << SRS_JFIELD_ORG("id", vhost->id) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("name", vhost->vhost) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("send_bytes", vhost->kbps->get_send_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("recv_bytes", vhost->kbps->get_recv_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_NAME("hls") << SRS_JOBJECT_START
                    << SRS_JFIELD_BOOL("enabled", hls_enabled) << SRS_JFIELD_CONT
                    << SRS_JFIELD_ORG("fragment", _srs_config->get_hls_fragment(vhost->vhost))
                << SRS_JOBJECT_END
            << SRS_JOBJECT_END;
    }
    ss << SRS_JARRAY_END;

    return ret;
}

int SrsStatistic::dumps_streams(stringstream& ss)
{
    int ret = ERROR_SUCCESS;

    ss << SRS_JARRAY_START;
    std::map<std::string, SrsStatisticStream*>::iterator it;
    for (it = streams.begin(); it != streams.end(); it++) {
        SrsStatisticStream* stream = it->second;
        if (it != streams.begin()) {
            ss << SRS_JFIELD_CONT;
        }

        int client_num = 0;
        std::map<int, SrsStatisticClient*>::iterator it_client;
        for (it_client = clients.begin(); it_client != clients.end(); it_client++) {
            SrsStatisticClient* client = it_client->second;
            if (client->stream == stream) {
                client_num++;
            }
        }

        ss << SRS_JOBJECT_START
                << SRS_JFIELD_ORG("id", stream->id) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("name", stream->stream) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("vhost", stream->vhost->id) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("app", stream->app) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("clients", client_num) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("send_bytes", stream->kbps->get_send_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("recv_bytes", stream->kbps->get_recv_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("live_ms", srs_get_system_time_ms()) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("status", stream->status) << SRS_JFIELD_CONT;

        if (!stream->has_video) {
            ss  << SRS_JFIELD_NULL("video") << SRS_JFIELD_CONT;
        } else {
            ss  << SRS_JFIELD_NAME("video")
                    << SRS_JOBJECT_START
                        << SRS_JFIELD_STR("codec", srs_codec_video2str(stream->vcodec)) << SRS_JFIELD_CONT
                        << SRS_JFIELD_STR("profile", srs_codec_avc_profile2str(stream->avc_profile)) << SRS_JFIELD_CONT
                        << SRS_JFIELD_ORG("level", srs_codec_avc_level2str(stream->avc_level))
                    << SRS_JOBJECT_END
                << SRS_JFIELD_CONT;
        }

        if (!stream->has_audio) {
            ss  << SRS_JFIELD_NULL("audio");
        } else {
            ss  << SRS_JFIELD_NAME("audio")
                    << SRS_JOBJECT_START
                        << SRS_JFIELD_STR("codec", srs_codec_audio2str(stream->acodec)) << SRS_JFIELD_CONT
                        << SRS_JFIELD_ORG("sample_rate", (int)flv_sample_rates[stream->asample_rate]) << SRS_JFIELD_CONT
                        << SRS_JFIELD_ORG("channel", (int)stream->asound_type + 1) << SRS_JFIELD_CONT
                        << SRS_JFIELD_STR("profile", srs_codec_aac_object2str(stream->aac_object))
                    << SRS_JOBJECT_END;
        }

        ss << SRS_JOBJECT_END;
    }
    ss << SRS_JARRAY_END;

    return ret;
}

SrsStatisticVhost* SrsStatistic::create_vhost(SrsRequest* req)
{
    SrsStatisticVhost* vhost = NULL;

    // create vhost if not exists.
    if (vhosts.find(req->vhost) == vhosts.end()) {
        vhost = new SrsStatisticVhost();
        vhost->vhost = req->vhost;
        vhosts[req->vhost] = vhost;
        return vhost;
    }

    vhost = vhosts[req->vhost];

    return vhost;
}

SrsStatisticStream* SrsStatistic::create_stream(SrsStatisticVhost* vhost, SrsRequest* req)
{
    std::string url = req->get_stream_url();

    SrsStatisticStream* stream = NULL;

    // create stream if not exists.
    if (streams.find(url) == streams.end()) {
        stream = new SrsStatisticStream();
        stream->vhost = vhost;
        stream->stream = req->stream;
        stream->app = req->app;
        stream->url = url;
        streams[url] = stream;
        return stream;
    }

    stream = streams[url];

    return stream;
}

<commit_msg>refine code, donot remove the detail when hls disabled.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2015 SRS(simple-rtmp-server)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <srs_app_statistic.hpp>

#include <unistd.h>
#include <sstream>
using namespace std;

#include <srs_rtmp_stack.hpp>
#include <srs_app_json.hpp>
#include <srs_protocol_kbps.hpp>
#include <srs_app_conn.hpp>
#include <srs_app_config.hpp>
#include <srs_kernel_utility.hpp>

int64_t srs_gvid = getpid();

int64_t srs_generate_id()
{
    return srs_gvid++;
}

SrsStatisticVhost::SrsStatisticVhost()
{
    id = srs_generate_id();

    kbps = new SrsKbps();
    kbps->set_io(NULL, NULL);
}

SrsStatisticVhost::~SrsStatisticVhost()
{
    srs_freep(kbps);
}

SrsStatisticStream::SrsStatisticStream()
{
    id = srs_generate_id();
    vhost = NULL;
    status = STATISTIC_STREAM_STATUS_IDLING;

    has_video = false;
    vcodec = SrsCodecVideoReserved;
    avc_profile = SrsAvcProfileReserved;
    avc_level = SrsAvcLevelReserved;

    has_audio = false;
    acodec = SrsCodecAudioReserved1;
    asample_rate = SrsCodecAudioSampleRateReserved;
    asound_type = SrsCodecAudioSoundTypeReserved;
    aac_object = SrsAacObjectTypeReserved;

    kbps = new SrsKbps();
    kbps->set_io(NULL, NULL);
}

SrsStatisticStream::~SrsStatisticStream()
{
    srs_freep(kbps);
}

void SrsStatisticStream::publish()
{
    status = STATISTIC_STREAM_STATUS_PUBLISHING;
}

void SrsStatisticStream::close()
{
    has_video = false;
    has_audio = false;
    status = STATISTIC_STREAM_STATUS_IDLING;
}

SrsStatistic* SrsStatistic::_instance = new SrsStatistic();

SrsStatistic::SrsStatistic()
{
    _server_id = srs_generate_id();

    kbps = new SrsKbps();
    kbps->set_io(NULL, NULL);
}

SrsStatistic::~SrsStatistic()
{
    srs_freep(kbps);

    if (true) {
        std::map<std::string, SrsStatisticVhost*>::iterator it;
        for (it = vhosts.begin(); it != vhosts.end(); it++) {
            SrsStatisticVhost* vhost = it->second;
            srs_freep(vhost);
        }
    }
    if (true) {
        std::map<std::string, SrsStatisticStream*>::iterator it;
        for (it = streams.begin(); it != streams.end(); it++) {
            SrsStatisticStream* stream = it->second;
            srs_freep(stream);
        }
    }
    if (true) {
        std::map<int, SrsStatisticClient*>::iterator it;
        for (it = clients.begin(); it != clients.end(); it++) {
            SrsStatisticClient* client = it->second;
            srs_freep(client);
        }
    }
}

SrsStatistic* SrsStatistic::instance()
{
    return _instance;
}

SrsStatisticStream* SrsStatistic::find_stream(int stream_id)
{
    std::map<int, SrsStatisticClient*>::iterator it;
    for (it = clients.begin(); it != clients.end(); it++) {
        SrsStatisticClient* client = it->second;
        SrsStatisticStream* stream = client->stream;

        if (stream_id == stream->id) {
            return stream;
        }
    }
    return NULL;
}

int SrsStatistic::on_video_info(SrsRequest* req,
    SrsCodecVideo vcodec, SrsAvcProfile avc_profile, SrsAvcLevel avc_level
) {
    int ret = ERROR_SUCCESS;

    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->has_video = true;
    stream->vcodec = vcodec;
    stream->avc_profile = avc_profile;
    stream->avc_level = avc_level;

    return ret;
}

int SrsStatistic::on_audio_info(SrsRequest* req,
    SrsCodecAudio acodec, SrsCodecAudioSampleRate asample_rate, SrsCodecAudioSoundType asound_type,
    SrsAacObjectType aac_object
) {
    int ret = ERROR_SUCCESS;

    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->has_audio = true;
    stream->acodec = acodec;
    stream->asample_rate = asample_rate;
    stream->asound_type = asound_type;
    stream->aac_object = aac_object;

    return ret;
}

void SrsStatistic::on_stream_publish(SrsRequest* req)
{
    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->publish();
}

void SrsStatistic::on_stream_close(SrsRequest* req)
{
    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    stream->close();
}

int SrsStatistic::on_client(int id, SrsRequest* req)
{
    int ret = ERROR_SUCCESS;

    SrsStatisticVhost* vhost = create_vhost(req);
    SrsStatisticStream* stream = create_stream(vhost, req);

    // create client if not exists
    SrsStatisticClient* client = NULL;
    if (clients.find(id) == clients.end()) {
        client = new SrsStatisticClient();
        client->id = id;
        client->stream = stream;
        clients[id] = client;
    } else {
        client = clients[id];
    }

    return ret;
}

void SrsStatistic::on_disconnect(int id)
{
    std::map<int, SrsStatisticClient*>::iterator it;
    it = clients.find(id);
    if (it != clients.end()) {
        SrsStatisticClient* client = it->second;
        srs_freep(client);
        clients.erase(it);
    }
}

void SrsStatistic::kbps_add_delta(SrsConnection* conn)
{
    int id = conn->srs_id();
    if (clients.find(id) == clients.end()) {
        return;
    }

    SrsStatisticClient* client = clients[id];

    // resample the kbps to collect the delta.
    conn->resample();

    // add delta of connection to kbps.
    // for next sample() of server kbps can get the stat.
    kbps->add_delta(conn);
    client->stream->kbps->add_delta(conn);
    client->stream->vhost->kbps->add_delta(conn);

    // cleanup the delta.
    conn->cleanup();
}

SrsKbps* SrsStatistic::kbps_sample()
{
    kbps->sample();
    if (true) {
        std::map<std::string, SrsStatisticVhost*>::iterator it;
        for (it = vhosts.begin(); it != vhosts.end(); it++) {
            SrsStatisticVhost* vhost = it->second;
            vhost->kbps->sample();
        }
    }
    if (true) {
        std::map<std::string, SrsStatisticStream*>::iterator it;
        for (it = streams.begin(); it != streams.end(); it++) {
            SrsStatisticStream* stream = it->second;
            stream->kbps->sample();
        }
    }

    return kbps;
}

int64_t SrsStatistic::server_id()
{
    return _server_id;
}

int SrsStatistic::dumps_vhosts(stringstream& ss)
{
    int ret = ERROR_SUCCESS;

    ss << SRS_JARRAY_START;
    std::map<std::string, SrsStatisticVhost*>::iterator it;
    for (it = vhosts.begin(); it != vhosts.end(); it++) {
        SrsStatisticVhost* vhost = it->second;
        if (it != vhosts.begin()) {
            ss << SRS_JFIELD_CONT;
        }

        // dumps the config of vhost.
        bool hls_enabled = _srs_config->get_hls_enabled(vhost->vhost);

        ss << SRS_JOBJECT_START
                << SRS_JFIELD_ORG("id", vhost->id) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("name", vhost->vhost) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("send_bytes", vhost->kbps->get_send_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("recv_bytes", vhost->kbps->get_recv_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_NAME("hls") << SRS_JOBJECT_START
                    << SRS_JFIELD_BOOL("enabled", hls_enabled);
        if (hls_enabled) {
            ss                                                  << SRS_JFIELD_CONT;
            ss      << SRS_JFIELD_ORG("fragment", _srs_config->get_hls_fragment(vhost->vhost));
        }
        ss      << SRS_JOBJECT_END
            << SRS_JOBJECT_END;
    }
    ss << SRS_JARRAY_END;

    return ret;
}

int SrsStatistic::dumps_streams(stringstream& ss)
{
    int ret = ERROR_SUCCESS;

    ss << SRS_JARRAY_START;
    std::map<std::string, SrsStatisticStream*>::iterator it;
    for (it = streams.begin(); it != streams.end(); it++) {
        SrsStatisticStream* stream = it->second;
        if (it != streams.begin()) {
            ss << SRS_JFIELD_CONT;
        }

        int client_num = 0;
        std::map<int, SrsStatisticClient*>::iterator it_client;
        for (it_client = clients.begin(); it_client != clients.end(); it_client++) {
            SrsStatisticClient* client = it_client->second;
            if (client->stream == stream) {
                client_num++;
            }
        }

        ss << SRS_JOBJECT_START
                << SRS_JFIELD_ORG("id", stream->id) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("name", stream->stream) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("vhost", stream->vhost->id) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("app", stream->app) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("clients", client_num) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("send_bytes", stream->kbps->get_send_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("recv_bytes", stream->kbps->get_recv_bytes()) << SRS_JFIELD_CONT
                << SRS_JFIELD_ORG("live_ms", srs_get_system_time_ms()) << SRS_JFIELD_CONT
                << SRS_JFIELD_STR("status", stream->status) << SRS_JFIELD_CONT;

        if (!stream->has_video) {
            ss  << SRS_JFIELD_NULL("video") << SRS_JFIELD_CONT;
        } else {
            ss  << SRS_JFIELD_NAME("video")
                    << SRS_JOBJECT_START
                        << SRS_JFIELD_STR("codec", srs_codec_video2str(stream->vcodec)) << SRS_JFIELD_CONT
                        << SRS_JFIELD_STR("profile", srs_codec_avc_profile2str(stream->avc_profile)) << SRS_JFIELD_CONT
                        << SRS_JFIELD_ORG("level", srs_codec_avc_level2str(stream->avc_level))
                    << SRS_JOBJECT_END
                << SRS_JFIELD_CONT;
        }

        if (!stream->has_audio) {
            ss  << SRS_JFIELD_NULL("audio");
        } else {
            ss  << SRS_JFIELD_NAME("audio")
                    << SRS_JOBJECT_START
                        << SRS_JFIELD_STR("codec", srs_codec_audio2str(stream->acodec)) << SRS_JFIELD_CONT
                        << SRS_JFIELD_ORG("sample_rate", (int)flv_sample_rates[stream->asample_rate]) << SRS_JFIELD_CONT
                        << SRS_JFIELD_ORG("channel", (int)stream->asound_type + 1) << SRS_JFIELD_CONT
                        << SRS_JFIELD_STR("profile", srs_codec_aac_object2str(stream->aac_object))
                    << SRS_JOBJECT_END;
        }

        ss << SRS_JOBJECT_END;
    }
    ss << SRS_JARRAY_END;

    return ret;
}

SrsStatisticVhost* SrsStatistic::create_vhost(SrsRequest* req)
{
    SrsStatisticVhost* vhost = NULL;

    // create vhost if not exists.
    if (vhosts.find(req->vhost) == vhosts.end()) {
        vhost = new SrsStatisticVhost();
        vhost->vhost = req->vhost;
        vhosts[req->vhost] = vhost;
        return vhost;
    }

    vhost = vhosts[req->vhost];

    return vhost;
}

SrsStatisticStream* SrsStatistic::create_stream(SrsStatisticVhost* vhost, SrsRequest* req)
{
    std::string url = req->get_stream_url();

    SrsStatisticStream* stream = NULL;

    // create stream if not exists.
    if (streams.find(url) == streams.end()) {
        stream = new SrsStatisticStream();
        stream->vhost = vhost;
        stream->stream = req->stream;
        stream->app = req->app;
        stream->url = url;
        streams[url] = stream;
        return stream;
    }

    stream = streams[url];

    return stream;
}

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#include <unotest/bootstrapfixturebase.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/bootstrap.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <comphelper/processfactory.hxx>

#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

using namespace ::com::sun::star;

// NB. this constructor is called before any tests are run, once for each
// test function in a rather non-intuitive way. This is why all the 'real'
// heavy lifting is deferred until setUp. setUp and tearDown are interleaved
// between the tests as you might expect.
test::BootstrapFixtureBase::BootstrapFixtureBase()
    : m_aSrcRootURL("file://"), m_aSolverRootURL( m_aSrcRootURL ),
      m_aWorkdirRootURL(m_aSrcRootURL)
{
#ifndef ANDROID
    const char* pSrcRoot = getenv( "SRC_ROOT" );
    CPPUNIT_ASSERT_MESSAGE("SRC_ROOT env variable not set", pSrcRoot != NULL && pSrcRoot[0] != 0);
    const char* pSolverRoot = getenv( "OUTDIR_FOR_BUILD" );
    CPPUNIT_ASSERT_MESSAGE("$OUTDIR_FOR_BUILD env variable not set", pSolverRoot != NULL && pSolverRoot[0] != 0);
    const char* pWorkdirRoot = getenv( "WORKDIR_FOR_BUILD" );
    CPPUNIT_ASSERT_MESSAGE("$WORKDIR_FOR_BUILD env variable not set", pWorkdirRoot != NULL && pWorkdirRoot[0] != 0);
#ifdef WNT
    if (pSrcRoot[1] == ':')
    {
        m_aSrcRootURL += "/";
    }
    if (pSolverRoot[1] == ':')
    {
        m_aSolverRootURL += "/";
    }
    if (pWorkdirRoot[1] == ':')
    {
        m_aWorkdirRootURL += "/";
    }
#endif
#else
    const char* pSrcRoot = "/assets";
    const char* pSolverRoot = "/assets";
    const char* pWorkdirRoot = "/assets";
#endif
    m_aSrcRootPath = OUString::createFromAscii( pSrcRoot );
    m_aSrcRootURL += m_aSrcRootPath;

    m_aSolverRootPath = OUString::createFromAscii( pSolverRoot );
    m_aSolverRootURL += m_aSolverRootPath;

    m_aWorkdirRootPath = OUString::createFromAscii( pWorkdirRoot );
    m_aWorkdirRootURL += m_aWorkdirRootPath;

}

test::BootstrapFixtureBase::~BootstrapFixtureBase()
{
}

OUString test::BootstrapFixtureBase::getURLFromSrc( const char *pPath )
{
    return m_aSrcRootURL + OUString::createFromAscii( pPath );
}

OUString test::BootstrapFixtureBase::getPathFromSrc( const char *pPath )
{
    return m_aSrcRootPath + OUString::createFromAscii( pPath );
}

OUString test::BootstrapFixtureBase::getURLFromWorkdir( const char *pPath )
{
    return m_aWorkdirRootURL + OUString::createFromAscii( pPath );
}

OUString test::BootstrapFixtureBase::getPathFromWorkdir( const char *pPath )
{
    return m_aWorkdirRootPath + OUString::createFromAscii( pPath );

}

void test::BootstrapFixtureBase::setUp()
{
    // set UserInstallation to user profile dir in test/user-template
    rtl::Bootstrap aDefaultVars;
    OUString sUserInstallURL = m_aSolverRootURL + OUString("/unittest");
    aDefaultVars.set(OUString("UserInstallation"), sUserInstallURL);

    m_xContext = comphelper::getProcessComponentContext();
    m_xFactory = m_xContext->getServiceManager();
    m_xSFactory = uno::Reference<lang::XMultiServiceFactory>(m_xFactory, uno::UNO_QUERY_THROW);
}

void test::BootstrapFixtureBase::tearDown()
{
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Fix URL creation<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "sal/config.h"

#include <cassert>

#include <unotest/bootstrapfixturebase.hxx>
#include <osl/file.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/bootstrap.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <comphelper/processfactory.hxx>

#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

using namespace ::com::sun::star;

namespace {

OUString getFileURLFromSystemPath(OUString const & path) {
    OUString url;
    osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath(path, url);
    assert(e == osl::FileBase::E_None);
    if (!url.endsWith("/")) {
        url += "/";
    }
    return url;
}

}

// NB. this constructor is called before any tests are run, once for each
// test function in a rather non-intuitive way. This is why all the 'real'
// heavy lifting is deferred until setUp. setUp and tearDown are interleaved
// between the tests as you might expect.
test::BootstrapFixtureBase::BootstrapFixtureBase()
{
#ifndef ANDROID
    const char* pSrcRoot = getenv( "SRC_ROOT" );
    CPPUNIT_ASSERT_MESSAGE("SRC_ROOT env variable not set", pSrcRoot != NULL && pSrcRoot[0] != 0);
    const char* pSolverRoot = getenv( "OUTDIR_FOR_BUILD" );
    CPPUNIT_ASSERT_MESSAGE("$OUTDIR_FOR_BUILD env variable not set", pSolverRoot != NULL && pSolverRoot[0] != 0);
    const char* pWorkdirRoot = getenv( "WORKDIR_FOR_BUILD" );
    CPPUNIT_ASSERT_MESSAGE("$WORKDIR_FOR_BUILD env variable not set", pWorkdirRoot != NULL && pWorkdirRoot[0] != 0);
#else
    const char* pSrcRoot = "/assets";
    const char* pSolverRoot = "/assets";
    const char* pWorkdirRoot = "/assets";
#endif
    m_aSrcRootPath = OUString::createFromAscii( pSrcRoot );
    m_aSrcRootURL = getFileURLFromSystemPath(m_aSrcRootPath);

    m_aSolverRootPath = OUString::createFromAscii( pSolverRoot );
    m_aSolverRootURL = getFileURLFromSystemPath(m_aSolverRootPath);

    m_aWorkdirRootPath = OUString::createFromAscii( pWorkdirRoot );
    m_aWorkdirRootURL = getFileURLFromSystemPath(m_aWorkdirRootPath);

}

test::BootstrapFixtureBase::~BootstrapFixtureBase()
{
}

OUString test::BootstrapFixtureBase::getURLFromSrc( const char *pPath )
{
    return m_aSrcRootURL + OUString::createFromAscii( pPath );
}

OUString test::BootstrapFixtureBase::getPathFromSrc( const char *pPath )
{
    return m_aSrcRootPath + OUString::createFromAscii( pPath );
}

OUString test::BootstrapFixtureBase::getURLFromWorkdir( const char *pPath )
{
    return m_aWorkdirRootURL + OUString::createFromAscii( pPath );
}

OUString test::BootstrapFixtureBase::getPathFromWorkdir( const char *pPath )
{
    return m_aWorkdirRootPath + OUString::createFromAscii( pPath );

}

void test::BootstrapFixtureBase::setUp()
{
    // set UserInstallation to user profile dir in test/user-template
    rtl::Bootstrap aDefaultVars;
    OUString sUserInstallURL = m_aSolverRootURL + OUString("/unittest");
    aDefaultVars.set(OUString("UserInstallation"), sUserInstallURL);

    m_xContext = comphelper::getProcessComponentContext();
    m_xFactory = m_xContext->getServiceManager();
    m_xSFactory = uno::Reference<lang::XMultiServiceFactory>(m_xFactory, uno::UNO_QUERY_THROW);
}

void test::BootstrapFixtureBase::tearDown()
{
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Token.h"
#include <cassert>
#include <memory>

using namespace std;
using Checkpoint = GraphLang::Parser::Checkpoint;

namespace GraphLang
{
namespace Tokenizer
{
	const TokenVisitor::RootTag TokenVisitor::Root = {};

	void TokenVisitor::operator()(Token& tok)
	{
		auto directive = visit(tok);

		switch(directive)
		{
		case Status::Stop:
			throw Impl::FullStopException{};
			return;
		case Status::StopBranch:
			return;
		case Status::Continue:
			tok.expose_children(*this);
		}
	}

	void TokenVisitor::operator()(Token& tok, RootTag)
	{
		try
		{
			operator()(tok);
		}
		catch(Impl::FullStopException)
		{
			// that's fine :)
		}

		return; // end of input
	}

	Token::Token()
	{
	}

	TokenParseResult Token::Parse(Parser& p)
	{
		assert(false);
		return TokenParseResult{ false, "CANT TRY TO PARSE A RAW (TOKEN)!!!!!" };
	}

	Token::~Token()
	{
	}

	Token::PrintablePosition Token::pos() const
	{
		return PrintablePosition(startpos, endpos);
	}

	TokenParseResult Identifier::Parse(Parser& input)
	{
		auto& in = input.i();
		Parser::Checkpoint ch(input, this);

		bool digitsOk = false;

		char c = in.peek();
		while(
			c == '_'
			|| ('a' <= c && c <= 'z')
			|| ('A' <= c && c <= 'Z')
			|| (digitsOk && '0' <= c && c <= '9')
			)
		{
			digitsOk = true;
			id += in.get();
			c = in.peek();
		}

		if (id.size() > 0)
		{
			ch.commit();
			return TokenParseResult{true, ""};
		}

		return TokenParseResult{false, "Couldn't match an ID."};
	}

	TokenParseResult Number::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		bool makeNegative = false;

		if (p.i().peek() == '-')
		{
			p.i().get();
			makeNegative = true;
			p.readws();
		}

		char firstChar = p.i().peek();
		if ('0' <= firstChar && firstChar <= '9')
		{
			p.i() >> num;
			if (makeNegative)
			{
				num *= -1;
			}

			ch.commit();

			return make_tuple(true, "");
		}

		return make_tuple(false, "Can't interpret as begining of number: "+firstChar);
	}

	TokenParseResult String::Parse(Parser& p)
	{
		Checkpoint ch(p, this);
		val = "";
		auto& i = p.i();

		char buf;

		i >> buf;
		if (buf != '"')
		{
			return TokenParseResult{false, "Expected '\"' to open string."};
		}

		while (i.peek() != '"')
		{
			i >> buf;

			if (buf == '\\')
			{
				i >> buf;

				switch (buf)
				{
				case '\\': val += '\\'; break;
				case 'n': val += '\n'; break;
				case 't': val += '\t'; break;
				case 'r': val += '\r'; break;
				case '"' : val += '"'; break;
				default:
					// This is such a dumb idea!
					throw string("Woah! Unknown escape sequence in string: \\"+buf);

				}

				continue;
			}

			val += buf;
		}

		i >> buf;
		if (buf != '"')
		{
			return TokenParseResult{ false, "Expected '\"' to close! string." };
		}

		ch.commit();
		return TokenParseResult{true, ""};
	}

	TokenParseResult Attribute::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		if (!get<0>(p.require(id)))
		{
			return make_tuple(false, "Couldn't match ID in AttributeKV-Pair");
		}

		if (!p.matchLiteral(":"))
		{
			return make_tuple(false, "Couldn't match colon in AttributeKV-Pair");
		}

		auto r = p.require(val);

		if (!get<0>(r))
		{
			return make_tuple(false, "Couldn't match val: (" + get<1>(r) + ") in AttributeKV-Pair");
		}

		ch.commit();

		return make_tuple(true, "");
	}

	void Attribute::expose_children(TokenVisitor& vis)
	{
		vis(id);
		vis(val);
	}

	TokenParseResult LiteralValue::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		// std::move({ make_unique<Number>(), make_unique<String>() })
		//vector<unique_ptr<Token>> tokens;

		//auto r = p.requireOneOf(std::move(tokens));

		auto r = p.oneOf<Number, String>();
		auto nodeptr = std::move(get<0>(r));

		if (nodeptr == nullptr)
		{
			return TokenParseResult{false, "Could not match a literal-value token!"};
		}

		ch.commit();
		val = std::move(nodeptr);

		return std::get<1>(r);
	}

	LiteralValue::LiteralValue(const LiteralValue& other)
	{
		val = nullptr;

		if (other.val != nullptr)
		{
			val = unique_ptr<Token>(other.val->clone());
		}
	}

	void LiteralValue::expose_children(TokenVisitor& v)
	{
		v(*val.get());
	}

	NodeValue LiteralValue::toNodeValue() const
	{
		if (String* strptr = dynamic_cast<String*>(val.get()))
		{
			return NodeValue(make_unique<std::string>(strptr->val));
		}

		if (Number* numptr = dynamic_cast<Number*>(val.get()))
		{
			return NodeValue(numptr->num);
		}

		return NodeValue{};
	}

	TokenParseResult Node::Parse(Parser& p)
	{
		// (hunter name:"Hunter" age:20)
		Checkpoint ch(p, this);

		TokenParseResult r;

		if (!p.matchLiteral("("))
		{
			return TokenParseResult{ false, "Nodes need to open with a left-paren." };
		}

		if (p.matchLiteral("?"))
		{
			// anonymous node!!
			identifier = Identifier();
			identifier.id = "";
		}
		else
		{
			// named node
			r = p.require(identifier);
			if (!get<0>(r))
			{
				return TokenParseResult{ false, "Couldn't locate an identifier for the node"};
			}
		}

		while (true)
		{
			Attribute attr;
			r = p.require(attr);

			if (! get<0>(r))
			{
				break;
			}

			attributes.push_back(make_unique<Attribute>(attr));
		}

		if (!p.matchLiteral(")"))
		{
			return TokenParseResult{ false, "Expected node to close with right-paren." };
		}

		ch.commit();
		return TokenParseResult{ true, ""};
	}

	Node::Node()
	{
	}

	Node::Node(const Node& other)
	{
		attributes.reserve(other.attributes.size());

		for (auto& p: other.attributes)
		{
			attributes.push_back(unique_ptr<Attribute>(static_cast<Attribute*>(p->clone())));
		}
	}

	void Node::expose_children(TokenVisitor& vis)
	{
		vis(identifier);
		for (auto& attr: attributes)
		{
			vis(*attr.get());
		}
	}

	::std::ostream& operator<<(::std::ostream& os, const Token::PrintablePosition& pos)
	{
		os << "(" << pos.b << ", " << pos.e << ")";
		return os;
	}

	TokenParseResult NodeArray::Parse(Parser& p)
	{
		Checkpoint ch(p, this);
		if (!p.matchLiteral("["))
		{
			// Single node
			Node node;
			auto r = p.require(node);

			if (!get<0>(r))
			{
				return TokenParseResult{ false,
					"Node-Array expected a single node in lieu of bracketed-array, but got (" + get<1>(r) + ")."
				};
			}

			nodes.push_back(node);

			ch.commit();
			return TokenParseResult{ true, "" };
		}

		if (p.matchLiteral("]"))
		{
			// empty vec of nodes
			ch.commit();
			return TokenParseResult{ true, "Empty NodeArray" };
		}

		Node primaryNode;
		auto r = p.require(primaryNode);
		if (!get<0>(r))
		{
			return TokenParseResult{false, "NodeArray expects non-empty NodeArray internals to start with a Node."};
		}

		nodes.push_back(primaryNode);

		while(p.matchLiteral(","))
		{
			Node extraNode;
			auto xnr = p.require(extraNode);

			if (!get<0>(xnr))
			{
				return TokenParseResult{ false, "NodeArray expects node to follow comma, but got: " + get<1>(xnr) };
			}

			nodes.push_back(extraNode);
		}

		// before consume ]

		if (!p.matchLiteral("]"))
		{
			return{false, "Couldn't match closing ] to NodeArray"};
		}

		ch.commit();

		return{ true, "" };
	}

	void NodeArray::expose_children(TokenVisitor& vis)
	{
		for (auto& node : nodes)
		{
			vis(node);
		}
	}

	TokenParseResult Relation::Parse(Parser& p)
	{
		// <-id- left relation
		// -id-> right relation
		// <-id-> both relation
		// -id- wtf is this???

		Checkpoint ch(p, this);

		if (p.matchLiteral("<-"))
		{
			direction.set(Direction::Left);
		}
		else
		{
			// at least need a - on the left
			if (!p.matchLiteral("-"))
			{
				return TokenParseResult{false, "Relation expected left to have either a <- or a -"};
			}
		}

		auto r = p.require(relationName);
		if (!get<0>(r))
		{
			return TokenParseResult{
				false,
				"Relation expects there to be an identifier, but: " + get<1>(r)
			};
		}

		if (p.matchLiteral("->"))
		{
			direction.set(Direction::Right);
		}
		else
		{
			// at least need a - on the right
			if (!p.matchLiteral("-"))
			{
				return TokenParseResult{ false, "Relation expected right to have either a -> or a -" };
			}
		}

		if (!direction.is(Direction::Left) && !direction.is(Direction::Right))
		{
			return TokenParseResult{ false, "Relation must be either left, right, or both!" };
		}

		ch.commit();
		return TokenParseResult{true, ""};
	}

	void Relation::expose_children(TokenVisitor& vis)
	{
		vis(relationName);
	}

	std::string Relation::Direction::pretty() const
	{
		switch (field)
		{
		case 0x0:						return "NONE?";
		case Dir::Left:					return "LEFT";
		case Dir::Right:				return "RIGHT";
		case Dir::Left | Dir::Right:	return "LEFT-RIGHT";
		default:
			assert(0);
			return "UNKNOWN!!!";
		}
	}

	TokenParseResult RelationStatement::Parse(Parser& p)
	{
		Checkpoint ch(p, this);
		NodeArray firstNode;

		auto r = p.require(firstNode);

		if (!get<0>(r))
		{
			return{false, "RelationStatement expects a nodearray but failed b/c: " + get<1>(r)};
		}

		nodeSets.push_back(std::move(firstNode));

		bool atLeast1 = false;

		while(true)
		{
			Relation rel;

			auto rrel = p.require(rel);

			if (!get<0>(rrel))
			{
				// no next relation
				break;
			}

			NodeArray arr;
			auto rarr = p.require(arr);

			if (!get<0>(rarr))
			{
				// should be a fatal error really
				return {false, "RelationStatement: expected NodeArray to follow relation, but got: " + get<1>(rarr)};
			}

			relations.emplace_back(std::move(rel));
			nodeSets.emplace_back(std::move(arr));

			atLeast1 = true;
		}

		if (!atLeast1)
		{
			return{false, "RelationStatement: Expected at least a single relation between nodes."};
		}

		if (!p.matchLiteral(";"))
		{
			return{ false, "RelationStatement expects to end with ';' and didn't." };
		}

		ch.commit();
		return {true, ""};
	}

	void RelationStatement::expose_children(TokenVisitor& vis)
	{
		for (auto& node : nodeSets) vis(node);
		for (auto& relation : relations) vis(relation);
	}

	TokenParseResult SingleNodeStatement::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		if (!get<0>(p.require(node)))
		{
			return{ false, "SingleNodeStatement requires a single node!" };
		}

		if (!p.matchLiteral(";"))
		{
			return{ false, "SingleNodeStatement expects a node to be followed by ';'" };
		}

		ch.commit();
		return{ true, "" };
	}

	void SingleNodeStatement::expose_children(TokenVisitor& vis)
	{
		vis(node);
	}

	TokenParseResult NodeArrayDeclarationStatement::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		if (!get<0>(p.require(nodearr)))
		{
			return{ false, "NodeArrayDeclarationStatement requires a node array!" };
		}

		if (!p.matchLiteral(";"))
		{
			return{ false, "NodeArrayDeclarationStatement expects a nodearray to be followed by ';'" };
		}

		ch.commit();
		return{ true, "" };
	}

	void NodeArrayDeclarationStatement::expose_children(TokenVisitor& vis)
	{
		vis(nodearr);
	}
}; // /namespace Tokenizer
}; // /namespace GraphLang

<commit_msg>Disable anon nodes<commit_after>#include "stdafx.h"
#include "Token.h"
#include <cassert>
#include <memory>

using namespace std;
using Checkpoint = GraphLang::Parser::Checkpoint;

namespace GraphLang
{
namespace Tokenizer
{
	const TokenVisitor::RootTag TokenVisitor::Root = {};

	void TokenVisitor::operator()(Token& tok)
	{
		auto directive = visit(tok);

		switch(directive)
		{
		case Status::Stop:
			throw Impl::FullStopException{};
			return;
		case Status::StopBranch:
			return;
		case Status::Continue:
			tok.expose_children(*this);
		}
	}

	void TokenVisitor::operator()(Token& tok, RootTag)
	{
		try
		{
			operator()(tok);
		}
		catch(Impl::FullStopException)
		{
			// that's fine :)
		}

		return; // end of input
	}

	Token::Token()
	{
	}

	TokenParseResult Token::Parse(Parser& p)
	{
		assert(false);
		return TokenParseResult{ false, "CANT TRY TO PARSE A RAW (TOKEN)!!!!!" };
	}

	Token::~Token()
	{
	}

	Token::PrintablePosition Token::pos() const
	{
		return PrintablePosition(startpos, endpos);
	}

	TokenParseResult Identifier::Parse(Parser& input)
	{
		auto& in = input.i();
		Parser::Checkpoint ch(input, this);

		bool digitsOk = false;

		char c = in.peek();
		while(
			c == '_'
			|| ('a' <= c && c <= 'z')
			|| ('A' <= c && c <= 'Z')
			|| (digitsOk && '0' <= c && c <= '9')
			)
		{
			digitsOk = true;
			id += in.get();
			c = in.peek();
		}

		if (id.size() > 0)
		{
			ch.commit();
			return TokenParseResult{true, ""};
		}

		return TokenParseResult{false, "Couldn't match an ID."};
	}

	TokenParseResult Number::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		bool makeNegative = false;

		if (p.i().peek() == '-')
		{
			p.i().get();
			makeNegative = true;
			p.readws();
		}

		char firstChar = p.i().peek();
		if ('0' <= firstChar && firstChar <= '9')
		{
			p.i() >> num;
			if (makeNegative)
			{
				num *= -1;
			}

			ch.commit();

			return make_tuple(true, "");
		}

		return make_tuple(false, "Can't interpret as begining of number: "+firstChar);
	}

	TokenParseResult String::Parse(Parser& p)
	{
		Checkpoint ch(p, this);
		val = "";
		auto& i = p.i();

		char buf;

		i >> buf;
		if (buf != '"')
		{
			return TokenParseResult{false, "Expected '\"' to open string."};
		}

		while (i.peek() != '"')
		{
			i >> buf;

			if (buf == '\\')
			{
				i >> buf;

				switch (buf)
				{
				case '\\': val += '\\'; break;
				case 'n': val += '\n'; break;
				case 't': val += '\t'; break;
				case 'r': val += '\r'; break;
				case '"' : val += '"'; break;
				default:
					// This is such a dumb idea!
					throw string("Woah! Unknown escape sequence in string: \\"+buf);

				}

				continue;
			}

			val += buf;
		}

		i >> buf;
		if (buf != '"')
		{
			return TokenParseResult{ false, "Expected '\"' to close! string." };
		}

		ch.commit();
		return TokenParseResult{true, ""};
	}

	TokenParseResult Attribute::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		if (!get<0>(p.require(id)))
		{
			return make_tuple(false, "Couldn't match ID in AttributeKV-Pair");
		}

		if (!p.matchLiteral(":"))
		{
			return make_tuple(false, "Couldn't match colon in AttributeKV-Pair");
		}

		auto r = p.require(val);

		if (!get<0>(r))
		{
			return make_tuple(false, "Couldn't match val: (" + get<1>(r) + ") in AttributeKV-Pair");
		}

		ch.commit();

		return make_tuple(true, "");
	}

	void Attribute::expose_children(TokenVisitor& vis)
	{
		vis(id);
		vis(val);
	}

	TokenParseResult LiteralValue::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		// std::move({ make_unique<Number>(), make_unique<String>() })
		//vector<unique_ptr<Token>> tokens;

		//auto r = p.requireOneOf(std::move(tokens));

		auto r = p.oneOf<Number, String>();
		auto nodeptr = std::move(get<0>(r));

		if (nodeptr == nullptr)
		{
			return TokenParseResult{false, "Could not match a literal-value token!"};
		}

		ch.commit();
		val = std::move(nodeptr);

		return std::get<1>(r);
	}

	LiteralValue::LiteralValue(const LiteralValue& other)
	{
		val = nullptr;

		if (other.val != nullptr)
		{
			val = unique_ptr<Token>(other.val->clone());
		}
	}

	void LiteralValue::expose_children(TokenVisitor& v)
	{
		v(*val.get());
	}

	NodeValue LiteralValue::toNodeValue() const
	{
		if (String* strptr = dynamic_cast<String*>(val.get()))
		{
			return NodeValue(make_unique<std::string>(strptr->val));
		}

		if (Number* numptr = dynamic_cast<Number*>(val.get()))
		{
			return NodeValue(numptr->num);
		}

		return NodeValue{};
	}

	TokenParseResult Node::Parse(Parser& p)
	{
		// (hunter name:"Hunter" age:20)
		Checkpoint ch(p, this);

		TokenParseResult r;

		if (!p.matchLiteral("("))
		{
			return TokenParseResult{ false, "Nodes need to open with a left-paren." };
		}

		// TODO(Hunter): enable anonymous node support
		if (false && p.matchLiteral("?"))
		{
			// anonymous node!!
			identifier = Identifier();
			identifier.id = "";
		}
		else
		{
			// named node
			r = p.require(identifier);
			if (!get<0>(r))
			{
				return TokenParseResult{ false, "Couldn't locate an identifier for the node"};
			}
		}

		while (true)
		{
			Attribute attr;
			r = p.require(attr);

			if (! get<0>(r))
			{
				break;
			}

			attributes.push_back(make_unique<Attribute>(attr));
		}

		if (!p.matchLiteral(")"))
		{
			return TokenParseResult{ false, "Expected node to close with right-paren." };
		}

		ch.commit();
		return TokenParseResult{ true, ""};
	}

	Node::Node()
	{
	}

	Node::Node(const Node& other)
	{
		attributes.reserve(other.attributes.size());

		for (auto& p: other.attributes)
		{
			attributes.push_back(unique_ptr<Attribute>(static_cast<Attribute*>(p->clone())));
		}
	}

	void Node::expose_children(TokenVisitor& vis)
	{
		vis(identifier);
		for (auto& attr: attributes)
		{
			vis(*attr.get());
		}
	}

	::std::ostream& operator<<(::std::ostream& os, const Token::PrintablePosition& pos)
	{
		os << "(" << pos.b << ", " << pos.e << ")";
		return os;
	}

	TokenParseResult NodeArray::Parse(Parser& p)
	{
		Checkpoint ch(p, this);
		if (!p.matchLiteral("["))
		{
			// Single node
			Node node;
			auto r = p.require(node);

			if (!get<0>(r))
			{
				return TokenParseResult{ false,
					"Node-Array expected a single node in lieu of bracketed-array, but got (" + get<1>(r) + ")."
				};
			}

			nodes.push_back(node);

			ch.commit();
			return TokenParseResult{ true, "" };
		}

		if (p.matchLiteral("]"))
		{
			// empty vec of nodes
			ch.commit();
			return TokenParseResult{ true, "Empty NodeArray" };
		}

		Node primaryNode;
		auto r = p.require(primaryNode);
		if (!get<0>(r))
		{
			return TokenParseResult{false, "NodeArray expects non-empty NodeArray internals to start with a Node."};
		}

		nodes.push_back(primaryNode);

		while(p.matchLiteral(","))
		{
			Node extraNode;
			auto xnr = p.require(extraNode);

			if (!get<0>(xnr))
			{
				return TokenParseResult{ false, "NodeArray expects node to follow comma, but got: " + get<1>(xnr) };
			}

			nodes.push_back(extraNode);
		}

		// before consume ]

		if (!p.matchLiteral("]"))
		{
			return{false, "Couldn't match closing ] to NodeArray"};
		}

		ch.commit();

		return{ true, "" };
	}

	void NodeArray::expose_children(TokenVisitor& vis)
	{
		for (auto& node : nodes)
		{
			vis(node);
		}
	}

	TokenParseResult Relation::Parse(Parser& p)
	{
		// <-id- left relation
		// -id-> right relation
		// <-id-> both relation
		// -id- wtf is this???

		Checkpoint ch(p, this);

		if (p.matchLiteral("<-"))
		{
			direction.set(Direction::Left);
		}
		else
		{
			// at least need a - on the left
			if (!p.matchLiteral("-"))
			{
				return TokenParseResult{false, "Relation expected left to have either a <- or a -"};
			}
		}

		auto r = p.require(relationName);
		if (!get<0>(r))
		{
			return TokenParseResult{
				false,
				"Relation expects there to be an identifier, but: " + get<1>(r)
			};
		}

		if (p.matchLiteral("->"))
		{
			direction.set(Direction::Right);
		}
		else
		{
			// at least need a - on the right
			if (!p.matchLiteral("-"))
			{
				return TokenParseResult{ false, "Relation expected right to have either a -> or a -" };
			}
		}

		if (!direction.is(Direction::Left) && !direction.is(Direction::Right))
		{
			return TokenParseResult{ false, "Relation must be either left, right, or both!" };
		}

		ch.commit();
		return TokenParseResult{true, ""};
	}

	void Relation::expose_children(TokenVisitor& vis)
	{
		vis(relationName);
	}

	std::string Relation::Direction::pretty() const
	{
		switch (field)
		{
		case 0x0:						return "NONE?";
		case Dir::Left:					return "LEFT";
		case Dir::Right:				return "RIGHT";
		case Dir::Left | Dir::Right:	return "LEFT-RIGHT";
		default:
			assert(0);
			return "UNKNOWN!!!";
		}
	}

	TokenParseResult RelationStatement::Parse(Parser& p)
	{
		Checkpoint ch(p, this);
		NodeArray firstNode;

		auto r = p.require(firstNode);

		if (!get<0>(r))
		{
			return{false, "RelationStatement expects a nodearray but failed b/c: " + get<1>(r)};
		}

		nodeSets.push_back(std::move(firstNode));

		bool atLeast1 = false;

		while(true)
		{
			Relation rel;

			auto rrel = p.require(rel);

			if (!get<0>(rrel))
			{
				// no next relation
				break;
			}

			NodeArray arr;
			auto rarr = p.require(arr);

			if (!get<0>(rarr))
			{
				// should be a fatal error really
				return {false, "RelationStatement: expected NodeArray to follow relation, but got: " + get<1>(rarr)};
			}

			relations.emplace_back(std::move(rel));
			nodeSets.emplace_back(std::move(arr));

			atLeast1 = true;
		}

		if (!atLeast1)
		{
			return{false, "RelationStatement: Expected at least a single relation between nodes."};
		}

		if (!p.matchLiteral(";"))
		{
			return{ false, "RelationStatement expects to end with ';' and didn't." };
		}

		ch.commit();
		return {true, ""};
	}

	void RelationStatement::expose_children(TokenVisitor& vis)
	{
		for (auto& node : nodeSets) vis(node);
		for (auto& relation : relations) vis(relation);
	}

	TokenParseResult SingleNodeStatement::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		if (!get<0>(p.require(node)))
		{
			return{ false, "SingleNodeStatement requires a single node!" };
		}

		if (!p.matchLiteral(";"))
		{
			return{ false, "SingleNodeStatement expects a node to be followed by ';'" };
		}

		ch.commit();
		return{ true, "" };
	}

	void SingleNodeStatement::expose_children(TokenVisitor& vis)
	{
		vis(node);
	}

	TokenParseResult NodeArrayDeclarationStatement::Parse(Parser& p)
	{
		Checkpoint ch(p, this);

		if (!get<0>(p.require(nodearr)))
		{
			return{ false, "NodeArrayDeclarationStatement requires a node array!" };
		}

		if (!p.matchLiteral(";"))
		{
			return{ false, "NodeArrayDeclarationStatement expects a nodearray to be followed by ';'" };
		}

		ch.commit();
		return{ true, "" };
	}

	void NodeArrayDeclarationStatement::expose_children(TokenVisitor& vis)
	{
		vis(nodearr);
	}
}; // /namespace Tokenizer
}; // /namespace GraphLang

<|endoftext|>


<commit_before>#include "application.h"

// POSIX
#include <fcntl.h>

// POSIX++
#include <cstring> // for strerror()
#include <cstdlib> // for exit

// STL
#include <atomic>
#include <list>

// PDTK
#include <cxxutils/error_helpers.h>

#ifndef VTERM_H
namespace terminal
{ const char* const critical = "\x1b[0;41;37;1mCRITICAL ERROR:\x1b[0m "; }
#endif

// atomic vars are to avoid race conditions
static std::atomic_int  s_return_value (0);
static std::atomic_bool s_run (true); // quit signal
static posix::fd_t s_pipeio[2] = { posix::invalid_descriptor }; //  execution stepper pipe

lockable<std::queue<vfunc>> Application::ms_signal_queue;
lockable<std::unordered_multimap<posix::fd_t, std::pair<EventFlags_t, vfdfunc>>> Application::ms_fd_signals;

enum {
  Read = 0,
  Write = 1,
};

Application::Application(void) noexcept
{
  if(s_pipeio[Read] == posix::invalid_descriptor) // if execution stepper pipe  hasn't been initialized yet
  {
    flaw(::pipe(s_pipeio) == posix::error_response, terminal::critical, std::exit(errno),,
         "Unable to create pipe for execution stepper: %s", std::strerror(errno))
    ::fcntl(s_pipeio[Read], F_SETFD, FD_CLOEXEC);
    ::fcntl(s_pipeio[Read], F_SETFL, O_NONBLOCK);
    EventBackend::init(); // initialize event backend
    EventBackend::watch(s_pipeio[Read], EventFlags::Readable); // watch for when execution stepper pipe has been triggered
  }
}

Application::~Application(void) noexcept
{
  if(s_pipeio[Read] != posix::invalid_descriptor)
  {
    EventBackend::destroy(); // shutdown event backend
    posix::close(s_pipeio[Read ]);
    posix::close(s_pipeio[Write]);
    s_pipeio[Read ] = posix::invalid_descriptor;
    s_pipeio[Write] = posix::invalid_descriptor;
  }
}

void Application::step(void) noexcept
{
  static const uint8_t dummydata = 0; // dummy content
  flaw(posix::write(s_pipeio[Write], &dummydata, 1) != 1, terminal::critical, /*std::exit(errno)*/,, // triggers execution stepper FD
       "Unable to trigger Object signal queue processor: %s", std::strerror(errno))
}

int Application::exec(void) noexcept // non-static function to ensure an instance of Application exists
{
  while(s_run) // while not quitting
  {
    EventBackend::getevents(); // get event queue
    for(const std::pair<posix::fd_t, EventData_t> pos : EventBackend::results) // process queued events
    {
      if(pos.first == s_pipeio[Read]) // if this is the execution stepper pipe (via Object::enqueue())
      {
        uint64_t discard;
        while(posix::read(pos.first, &discard, sizeof(discard)) != posix::error_response);

        // execute queue of object signal calls
        static std::queue<vfunc> exec_queue;
        if(exec_queue.empty()) // if not currently executing (recursive or multithread exec() calls?)
        {
          ms_signal_queue.lock(); // get exclusive access (make thread-safe)
          exec_queue.swap(ms_signal_queue); // swap the queues
          ms_signal_queue.unlock(); // access is no longer needed

          while(!exec_queue.empty()) // while still have object signals to execute
          {
            exec_queue.front()(); // execute current object signal/callback
            exec_queue.pop(); // discard current object signal
          }
        }
      }
      else // if this was a watched FD
      {
        ms_fd_signals.lock(); // get exclusive access (make thread-safe)
        auto entries = ms_fd_signals.equal_range(pos.first); // get all the callback entries for that FD
        std::list<std::pair<posix::fd_t, std::pair<EventFlags_t, vfdfunc>>> exec_fds(entries.first, entries.second); // copy entries
        ms_fd_signals.unlock(); // access is no longer needed
        for(auto& entry : exec_fds) // for each FD
        {
          if(entry.second.first.isSet(pos.second.flags)) // if the flags match
            entry.second.second(pos.first, pos.second); // call the fuction with the FD and triggering EventFlag
        }
      }
    }
  }
  return s_return_value; // quit() has been called, return value specified
}

void Application::quit(int return_value) noexcept // soft application exit (allows event queues to complete)
{
  if(s_run) // if not already quitting
  {
    s_return_value = return_value; // set application return value
    s_run = false; // indicate program must quit
  }
}
<commit_msg>readd vterm dependency<commit_after>#include "application.h"

// POSIX
#include <fcntl.h>

// POSIX++
#include <cstring> // for strerror()
#include <cstdlib> // for exit

// STL
#include <atomic>
#include <list>

// PDTK
#include <cxxutils/vterm.h>
#include <cxxutils/error_helpers.h>

// atomic vars are to avoid race conditions
static std::atomic_int  s_return_value (0);
static std::atomic_bool s_run (true); // quit signal
static posix::fd_t s_pipeio[2] = { posix::invalid_descriptor }; //  execution stepper pipe

lockable<std::queue<vfunc>> Application::ms_signal_queue;
lockable<std::unordered_multimap<posix::fd_t, std::pair<EventFlags_t, vfdfunc>>> Application::ms_fd_signals;

enum {
  Read = 0,
  Write = 1,
};

Application::Application(void) noexcept
{
  if(s_pipeio[Read] == posix::invalid_descriptor) // if execution stepper pipe  hasn't been initialized yet
  {
    flaw(::pipe(s_pipeio) == posix::error_response, terminal::critical, std::exit(errno),,
         "Unable to create pipe for execution stepper: %s", std::strerror(errno))
    ::fcntl(s_pipeio[Read], F_SETFD, FD_CLOEXEC);
    ::fcntl(s_pipeio[Read], F_SETFL, O_NONBLOCK);
    EventBackend::init(); // initialize event backend
    EventBackend::watch(s_pipeio[Read], EventFlags::Readable); // watch for when execution stepper pipe has been triggered
  }
}

Application::~Application(void) noexcept
{
  if(s_pipeio[Read] != posix::invalid_descriptor)
  {
    EventBackend::destroy(); // shutdown event backend
    posix::close(s_pipeio[Read ]);
    posix::close(s_pipeio[Write]);
    s_pipeio[Read ] = posix::invalid_descriptor;
    s_pipeio[Write] = posix::invalid_descriptor;
  }
}

void Application::step(void) noexcept
{
  static const uint8_t dummydata = 0; // dummy content
  flaw(posix::write(s_pipeio[Write], &dummydata, 1) != 1, terminal::critical, /*std::exit(errno)*/,, // triggers execution stepper FD
       "Unable to trigger Object signal queue processor: %s", std::strerror(errno))
}

int Application::exec(void) noexcept // non-static function to ensure an instance of Application exists
{
  while(s_run) // while not quitting
  {
    EventBackend::getevents(); // get event queue
    for(const std::pair<posix::fd_t, EventData_t> pos : EventBackend::results) // process queued events
    {
      if(pos.first == s_pipeio[Read]) // if this is the execution stepper pipe (via Object::enqueue())
      {
        uint64_t discard;
        while(posix::read(pos.first, &discard, sizeof(discard)) != posix::error_response);

        // execute queue of object signal calls
        static std::queue<vfunc> exec_queue;
        if(exec_queue.empty()) // if not currently executing (recursive or multithread exec() calls?)
        {
          ms_signal_queue.lock(); // get exclusive access (make thread-safe)
          exec_queue.swap(ms_signal_queue); // swap the queues
          ms_signal_queue.unlock(); // access is no longer needed

          while(!exec_queue.empty()) // while still have object signals to execute
          {
            exec_queue.front()(); // execute current object signal/callback
            exec_queue.pop(); // discard current object signal
          }
        }
      }
      else // if this was a watched FD
      {
        ms_fd_signals.lock(); // get exclusive access (make thread-safe)
        auto entries = ms_fd_signals.equal_range(pos.first); // get all the callback entries for that FD
        std::list<std::pair<posix::fd_t, std::pair<EventFlags_t, vfdfunc>>> exec_fds(entries.first, entries.second); // copy entries
        ms_fd_signals.unlock(); // access is no longer needed
        for(auto& entry : exec_fds) // for each FD
        {
          if(entry.second.first.isSet(pos.second.flags)) // if the flags match
            entry.second.second(pos.first, pos.second); // call the fuction with the FD and triggering EventFlag
        }
      }
    }
  }
  return s_return_value; // quit() has been called, return value specified
}

void Application::quit(int return_value) noexcept // soft application exit (allows event queues to complete)
{
  if(s_run) // if not already quitting
  {
    s_return_value = return_value; // set application return value
    s_run = false; // indicate program must quit
  }
}
<|endoftext|>


<commit_before>
/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TBenchmark.h"
#include "TROOT.h"
#include "TStopwatch.h"

TBenchmark *gBenchmark = 0;

ClassImp(TBenchmark)

//______________________________________________________________________________
//////////////////////////////////////////////////////////////////////////
//
// This class is a ROOT utility to help benchmarking applications
//
//  Examples of use of this class are given in the tutorials macros.
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
TBenchmark::TBenchmark(): TNamed()
{
//*-*-*-*-*-*-*-*-*-*-*Benchmark default constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =============================

   fNbench   = 0;
   fNmax     = 20;
   fNames    = 0;
   fRealTime = 0;
   fCpuTime  = 0;
   fTimer    = 0;
}

//______________________________________________________________________________
TBenchmark::TBenchmark(const TBenchmark& bm) :
  TNamed(bm),
  fNbench(bm.fNbench),
  fNmax(bm.fNmax),
  fNames(0),
  fRealTime(0),
  fCpuTime(0),
  fTimer(0)
{
   //copy constructor
   fNames    = new TString[fNmax];
   fRealTime = new Float_t[fNmax];
   fCpuTime  = new Float_t[fNmax];
   fTimer    = new TStopwatch[fNmax];

   for(Int_t i = 0; i<fNmax; ++i) {
      fNames[i] = bm.fNames[i];
      fRealTime[i] = bm.fRealTime[i];
      fCpuTime[i] = bm.fCpuTime[i];
      fTimer[i] = bm.fTimer[i];
   }
}

//______________________________________________________________________________
TBenchmark& TBenchmark::operator=(const TBenchmark& bm)
{
   //assignment operator
   if(this!=&bm) {
      TNamed::operator=(bm);
      fNbench=bm.fNbench;
      fNmax=bm.fNmax;

      delete [] fNames;
      delete [] fRealTime;
      delete [] fCpuTime;
      delete [] fTimer;

      fNames    = new TString[fNmax];
      fRealTime = new Float_t[fNmax];
      fCpuTime  = new Float_t[fNmax];
      fTimer    = new TStopwatch[fNmax];

      for(Int_t i = 0; i<fNmax; ++i) {
         fNames[i] = bm.fNames[i];
         fRealTime[i] = bm.fRealTime[i];
         fCpuTime[i] = bm.fCpuTime[i];
         fTimer[i] = bm.fTimer[i];
      }
   }
   return *this;
}

//______________________________________________________________________________
TBenchmark::~TBenchmark()
{
//*-*-*-*-*-*-*-*-*-*-*Benchmark default destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  ============================

   fNbench   = 0;
   if (fNames)    { delete [] fNames;    fNames  = 0;}
   if (fRealTime) { delete [] fRealTime; fRealTime  = 0;}
   if (fCpuTime)  { delete [] fCpuTime;  fCpuTime  = 0;}
   if (fTimer  )  { delete [] fTimer;    fTimer  = 0;}
}

//______________________________________________________________________________
Int_t TBenchmark::GetBench(const char *name) const
{
//*-*-*-*-*-*-*-*-*-*-*Returns index of Benchmark name*-*-*-*-*-*-*-*
//*-*                  ===============================

   for (Int_t i=0;i<fNbench;i++) {
      if (!strcmp(name,(const char*)fNames[i])) return i;
   }
   return -1;
}

//______________________________________________________________________________
Float_t TBenchmark::GetCpuTime(const char *name)
{
//*-*-*-*-*-*-*-*-*-*-*Returns Cpu time used by Benchmark name*-*-*-*-*-*-*-*
//*-*                  =======================================

   Int_t bench = GetBench(name);
   if (bench >= 0) return fCpuTime[bench];
   else            return 0;
}

//______________________________________________________________________________
Float_t TBenchmark::GetRealTime(const char *name)
{
//*-*-*-*-*-*-*-*-*-*-*Returns Realtime used by Benchmark name*-*-*-*-*-*-*-*
//*-*                  =======================================

   Int_t bench = GetBench(name);
   if (bench >= 0) return fRealTime[bench];
   else            return 0;
}

//______________________________________________________________________________
void TBenchmark::Print(const char *name) const
{
//*-*-*-*-*-*-*-*-*-*-*Prints parameters of Benchmark name*-*-*-*-*-*-*-*-*-*
//*-*                  ===================================

   Int_t bench = GetBench(name);
   if (bench < 0) return;
   Printf("%-10s: Real Time = %6.2f seconds Cpu Time = %6.2f seconds",name,fRealTime[bench],fCpuTime[bench]);
}

//______________________________________________________________________________
void TBenchmark::Reset()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*-*Reset all Benchmarks*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                        ====================

   fNbench = 0;

}

//______________________________________________________________________________
void TBenchmark::Show(const char *name)
{
//*-*-*-*-*-*-*-*-*Stops Benchmark name and Prints results*-*-*-*-*-*-*-*-*-*
//*-*              =======================================

   Stop(name);
   Print((char*)name);
}

//______________________________________________________________________________
void TBenchmark::Start(const char *name)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*Starts Benchmark name*-*-*-*-*-*-*-*-*-*
//*-*                          =====================
//*-*
//*-*   An independent timer (see class TStopwatch) is started.
//*-*   the name of the benchmark is entered into the list of benchmarks.
//*-*   Benchmark can be stopped via TBenchmark::Stop
//*-*   Results can be printed via TBenchmark::Print
//*-*   TBenchmark::Show can be used to stop benchmark and print results.
//*-*   If name is an already existing benchmark, existing parameters are reset.
//*-*   A summary of all benchmarks can be seen via TBenchmark::Summary.
//*-*
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
   if (!fNames) {
      fNames    = new TString[fNmax];
      fRealTime = new Float_t[fNmax];
      fCpuTime  = new Float_t[fNmax];
      fTimer    = new TStopwatch[fNmax];
   }
   Int_t bench = GetBench(name);
   if (bench < 0 && fNbench < fNmax ) {
   // define a new benchmark to Start
      fNames[fNbench] = name;
      bench = fNbench;
      fNbench++;
      fTimer[bench].Reset();
      fTimer[bench].Start();
      fRealTime[bench] = 0;
      fCpuTime[bench]  = 0;
   } else if (bench >=0) {
   // Resume the existen benchmark
      fTimer[bench].Continue();
   }
   else
      Warning("Start","too many benches");

}

//______________________________________________________________________________
void TBenchmark::Stop(const char *name)
{
//*-*-*-*-*-*-*-*-*-*-*Terminates Benchmark name*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================

   Int_t bench = GetBench(name);
   if (bench < 0) return;

   fTimer[bench].Stop();
   fRealTime[bench] = fTimer[bench].RealTime();
   fCpuTime[bench]  = fTimer[bench].CpuTime();

}

//______________________________________________________________________________
void TBenchmark::Summary(Float_t &rt, Float_t &cp)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*-*Prints a summary of all benchmarks*-*-*-*-*-*-*-*
//*-*                        ==================================

   rt = 0;
   cp = 0;
   for (Int_t i=0;i<fNbench;i++) {
      Printf("%-10s: Real Time = %6.2f seconds Cpu Time = %6.2f seconds",(const char*)fNames[i],fRealTime[i],fCpuTime[i]);
      rt += fRealTime[i];
      cp += fCpuTime[i];
   }
   Printf("%-10s: Real Time = %6.2f seconds Cpu Time = %6.2f seconds","TOTAL",rt,cp);

}
<commit_msg>Fix comment in Start(), starting of an existing benchmark will resume the benchmark, not reset it.<commit_after>
/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TBenchmark.h"
#include "TROOT.h"
#include "TStopwatch.h"

TBenchmark *gBenchmark = 0;

ClassImp(TBenchmark)

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TBenchmark                                                           //
//                                                                      //
// This class is a ROOT utility to help benchmarking applications       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
TBenchmark::TBenchmark(): TNamed()
{
   // Benchmark default constructor

   fNbench   = 0;
   fNmax     = 20;
   fNames    = 0;
   fRealTime = 0;
   fCpuTime  = 0;
   fTimer    = 0;
}

//______________________________________________________________________________
TBenchmark::TBenchmark(const TBenchmark& bm) :
  TNamed(bm),
  fNbench(bm.fNbench),
  fNmax(bm.fNmax),
  fNames(0),
  fRealTime(0),
  fCpuTime(0),
  fTimer(0)
{
   // Copy constructor.

   fNames    = new TString[fNmax];
   fRealTime = new Float_t[fNmax];
   fCpuTime  = new Float_t[fNmax];
   fTimer    = new TStopwatch[fNmax];

   for(Int_t i = 0; i<fNmax; ++i) {
      fNames[i] = bm.fNames[i];
      fRealTime[i] = bm.fRealTime[i];
      fCpuTime[i] = bm.fCpuTime[i];
      fTimer[i] = bm.fTimer[i];
   }
}

//______________________________________________________________________________
TBenchmark& TBenchmark::operator=(const TBenchmark& bm)
{
   // Assignment operator.

   if (this!=&bm) {
      TNamed::operator=(bm);
      fNbench=bm.fNbench;
      fNmax=bm.fNmax;

      delete [] fNames;
      delete [] fRealTime;
      delete [] fCpuTime;
      delete [] fTimer;

      fNames    = new TString[fNmax];
      fRealTime = new Float_t[fNmax];
      fCpuTime  = new Float_t[fNmax];
      fTimer    = new TStopwatch[fNmax];

      for(Int_t i = 0; i<fNmax; ++i) {
         fNames[i] = bm.fNames[i];
         fRealTime[i] = bm.fRealTime[i];
         fCpuTime[i] = bm.fCpuTime[i];
         fTimer[i] = bm.fTimer[i];
      }
   }
   return *this;
}

//______________________________________________________________________________
TBenchmark::~TBenchmark()
{
   // Benchmark destructor.

   fNbench   = 0;
   if (fNames)    { delete [] fNames;    fNames  = 0;}
   if (fRealTime) { delete [] fRealTime; fRealTime  = 0;}
   if (fCpuTime)  { delete [] fCpuTime;  fCpuTime  = 0;}
   if (fTimer  )  { delete [] fTimer;    fTimer  = 0;}
}

//______________________________________________________________________________
Int_t TBenchmark::GetBench(const char *name) const
{
   // Returns index of Benchmark name.

   for (Int_t i=0;i<fNbench;i++) {
      if (!strcmp(name,(const char*)fNames[i])) return i;
   }
   return -1;
}

//______________________________________________________________________________
Float_t TBenchmark::GetCpuTime(const char *name)
{
   // Returns Cpu time used by Benchmark name.

   Int_t bench = GetBench(name);
   if (bench >= 0) return fCpuTime[bench];
   else            return 0;
}

//______________________________________________________________________________
Float_t TBenchmark::GetRealTime(const char *name)
{
   // Returns Realtime used by Benchmark name.

   Int_t bench = GetBench(name);
   if (bench >= 0) return fRealTime[bench];
   else            return 0;
}

//______________________________________________________________________________
void TBenchmark::Print(const char *name) const
{
   // Prints parameters of Benchmark name.

   Int_t bench = GetBench(name);
   if (bench < 0) return;
   Printf("%-10s: Real Time = %6.2f seconds Cpu Time = %6.2f seconds",name,fRealTime[bench],fCpuTime[bench]);
}

//______________________________________________________________________________
void TBenchmark::Reset()
{
   // Reset all Benchmarks

   fNbench = 0;
}

//______________________________________________________________________________
void TBenchmark::Show(const char *name)
{
   // Stops Benchmark name and Prints results

   Stop(name);
   Print((char*)name);
}

//______________________________________________________________________________
void TBenchmark::Start(const char *name)
{
   // Starts Benchmark with the specified name.
   //
   // An independent timer (see class TStopwatch) is started.
   // The name of the benchmark is entered into the list of benchmarks.
   // Benchmark can be stopped via TBenchmark::Stop().
   // Results can be printed via TBenchmark::Print().
   // TBenchmark::Show() can be used to stop benchmark and print results.
   // If name is an already existing benchmark, timing will resume.
   // A summary of all benchmarks can be seen via TBenchmark::Summary().

   if (!fNames) {
      fNames    = new TString[fNmax];
      fRealTime = new Float_t[fNmax];
      fCpuTime  = new Float_t[fNmax];
      fTimer    = new TStopwatch[fNmax];
   }
   Int_t bench = GetBench(name);
   if (bench < 0 && fNbench < fNmax ) {
      // define a new benchmark to Start
      fNames[fNbench] = name;
      bench = fNbench;
      fNbench++;
      fTimer[bench].Reset();
      fTimer[bench].Start();
      fRealTime[bench] = 0;
      fCpuTime[bench]  = 0;
   } else if (bench >= 0) {
      // Resume the existing benchmark
      fTimer[bench].Continue();
   }
   else
      Warning("Start","too many benchemarks");
}

//______________________________________________________________________________
void TBenchmark::Stop(const char *name)
{
   // Terminates Benchmark with specified name.

   Int_t bench = GetBench(name);
   if (bench < 0) return;

   fTimer[bench].Stop();
   fRealTime[bench] = fTimer[bench].RealTime();
   fCpuTime[bench]  = fTimer[bench].CpuTime();
}

//______________________________________________________________________________
void TBenchmark::Summary(Float_t &rt, Float_t &cp)
{
   // Prints a summary of all benchmarks.

   rt = 0;
   cp = 0;
   for (Int_t i=0;i<fNbench;i++) {
      Printf("%-10s: Real Time = %6.2f seconds Cpu Time = %6.2f seconds",(const char*)fNames[i],fRealTime[i],fCpuTime[i]);
      rt += fRealTime[i];
      cp += fCpuTime[i];
   }
   Printf("%-10s: Real Time = %6.2f seconds Cpu Time = %6.2f seconds","TOTAL",rt,cp);
}
<|endoftext|>


<commit_before>#include "trajopt/configuration_space.hpp"
#include <boost/foreach.hpp>
#include "trajopt/rave_utils.hpp"
#include "utils/math.hpp"
using namespace OpenRAVE;
using namespace util;

// TODO: configuration should know something about what dofs are part of SO(1), SO(2) etc for functions like RandomDOFValues

namespace trajopt {

void RobotAndDOF::SetDOFValues(const DblVec& dofs) {
  if (affinedofs != 0) {
    OR::Transform T;
    OR::RaveGetTransformFromAffineDOFValues(T, dofs.begin()+joint_inds.size(), affinedofs, rotationaxis, true);
    robot->SetTransform(T);
    if (joint_inds.size() > 0)
      robot->SetDOFValues(dofs, false, joint_inds);
  }
  else {
    robot->SetDOFValues(dofs, false, joint_inds);
  }
}

DblVec RobotAndDOF::GetDOFValues() {
  DblVec out;
  if (joint_inds.size() > 0):
    robot->GetDOFValues(out, joint_inds);
  if (affinedofs != 0) {
    out.resize(GetDOF());
    OR::Transform T = robot->GetTransform();
    OR::RaveGetAffineDOFValuesFromTransform(out.begin() + joint_inds.size(), T, affinedofs, rotationaxis);
  }
  return out;
}

void RobotAndDOF::SetRobotActiveDOFs()  {
  RobotBasePtr robot1 = boost::dynamic_pointer_cast<RobotBase>(robot); // since robot is just a kinbody
  vector<int> current_active = robot1->GetActiveDOFIndices();
  if (robot1->GetActiveDOF() != GetDOF() || !std::equal(current_active.begin(), current_active.end(), joint_inds.begin()))
    robot1->SetActiveDOFs(joint_inds, affinedofs);
}

void RobotAndDOF::GetDOFLimits(DblVec& lower, DblVec& upper) const {
  if (joint_inds.size() > 0)
    robot->GetDOFLimits(lower, upper, joint_inds);
  const int translation_dofs[3] = {DOF_X, DOF_Y, DOF_Z};
  for (int i=0; i < 3; ++i) {
    if (affinedofs & translation_dofs[i]) {
      lower.push_back(-INFINITY);
      upper.push_back(INFINITY);
    }
  }
  if (affinedofs & DOF_RotationMask) {
    if (affinedofs & DOF_RotationAxis) {
      lower.push_back(-INFINITY);
      upper.push_back(INFINITY);
    }
    else if (affinedofs & DOF_Rotation3D) {
      for (int i=0; i < 3; ++i) {
        lower.push_back(-INFINITY);
        upper.push_back(INFINITY);
      }
    }
    else if (affinedofs & DOF_Rotation3D) {
      for (int i=0; i < 3; ++i) {
        lower.push_back(-INFINITY);
        upper.push_back(INFINITY);
      }
    }
    else if (affinedofs & DOF_RotationQuat) {
      for (int i=0; i < 4; ++i) {
        lower.push_back(-1);
        upper.push_back(1);
      }
    }
    else throw OR::openrave_exception("invalid rotation dofs", ORE_InvalidArguments);
  }
}
int RobotAndDOF::GetDOF() const {
  return joint_inds.size() + RaveGetAffineDOF(affinedofs);
}
DblMatrix RobotAndDOF::PositionJacobian(int link_ind, const OR::Vector& pt) const {
  Configuration::SaverPtr saver = const_cast<RobotAndDOF*>(this)->Save();
  const_cast<RobotAndDOF*>(this)->SetRobotActiveDOFs();
  vector<double> jacdata;
  boost::dynamic_pointer_cast<RobotBase>(robot)->CalculateActiveJacobian(link_ind, pt, jacdata);
  return Eigen::Map<DblMatrix>(jacdata.data(), 3, GetDOF());
}
DblMatrix RobotAndDOF::RotationJacobian(int link_ind) const {
  Configuration::SaverPtr saver = const_cast<RobotAndDOF*>(this)->Save();
  const_cast<RobotAndDOF*>(this)->SetRobotActiveDOFs();
  vector<double> jacdata;
  boost::dynamic_pointer_cast<RobotBase>(robot)->ComputeJacobianAxisAngle(link_ind, jacdata);
  return Eigen::Map<DblMatrix>(jacdata.data(), 3, GetDOF());
}
bool RobotAndDOF::DoesAffect(const KinBody::Link& link) {
  if (affinedofs > 0) return true;
  else if (link.GetParent() == GetRobot()) return trajopt::DoesAffect(*GetRobot(), joint_inds, GetRobotLinkIndex(*GetRobot(), link));
  else return false;
}

std::vector<KinBody::LinkPtr> RobotAndDOF::GetAffectedLinks() {
  vector<int> inds;
  std::vector<KinBody::LinkPtr> out;
  GetAffectedLinks(out,false,inds);
  return out;
}

void RobotAndDOF::GetAffectedLinks(std::vector<KinBody::LinkPtr>& links, bool only_with_geom, vector<int>& link_inds) {
  links.clear();
  link_inds.clear();
  BOOST_FOREACH(const KinBody::LinkPtr& link, GetRobot()->GetLinks()) {
    if (this->DoesAffect(*link) && !(only_with_geom && link->GetGeometries().empty())) {
      links.push_back(link);
      link_inds.push_back(link->GetIndex());
    }
  }

  vector<KinBodyPtr> grabbed;
  boost::dynamic_pointer_cast<RobotBase>(robot)->GetGrabbed(grabbed);
  BOOST_FOREACH(const KinBodyPtr& body, grabbed) {
    KinBody::LinkPtr grabberLink = boost::dynamic_pointer_cast<RobotBase>(robot)->IsGrabbing(body);
    assert(grabberLink);
    BOOST_FOREACH(const KinBody::LinkPtr& link, body->GetLinks()) {
      if (link->GetGeometries().size() > 0) {
        links.push_back(link);
        link_inds.push_back(grabberLink->GetIndex());
      }
    }
  }

}

vector<KinBodyPtr> RobotAndDOF::GetBodies() {
  std::set<KinBodyPtr> bodies;
  robot->GetAttached(bodies);
  return vector<KinBodyPtr> (bodies.begin(), bodies.end());
}

DblVec RobotAndDOF::RandomDOFValues() {
  int ndof = GetDOF();
  DblVec lower, upper;
  GetDOFLimits(lower, upper);
  DblVec out(ndof);
  for (int i=0; i < ndof; ++i) {
    // TODO this is only right for a circular joint!!
    lower[i] = fmax(lower[i], -2*M_PI);
    upper[i] = fmin(upper[i], 2*M_PI);
    out[i] = lower[i] + randf() * (upper[i] - lower[i]);
  }
  return out;
}

}
<commit_msg>Fixed typo<commit_after>#include "trajopt/configuration_space.hpp"
#include <boost/foreach.hpp>
#include "trajopt/rave_utils.hpp"
#include "utils/math.hpp"
using namespace OpenRAVE;
using namespace util;

// TODO: configuration should know something about what dofs are part of SO(1), SO(2) etc for functions like RandomDOFValues

namespace trajopt {

void RobotAndDOF::SetDOFValues(const DblVec& dofs) {
  if (affinedofs != 0) {
    OR::Transform T;
    OR::RaveGetTransformFromAffineDOFValues(T, dofs.begin()+joint_inds.size(), affinedofs, rotationaxis, true);
    robot->SetTransform(T);
    if (joint_inds.size() > 0)
      robot->SetDOFValues(dofs, false, joint_inds);
  }
  else {
    robot->SetDOFValues(dofs, false, joint_inds);
  }
}

DblVec RobotAndDOF::GetDOFValues() {
  DblVec out;
  if (joint_inds.size() > 0)
    robot->GetDOFValues(out, joint_inds);
  if (affinedofs != 0) {
    out.resize(GetDOF());
    OR::Transform T = robot->GetTransform();
    OR::RaveGetAffineDOFValuesFromTransform(out.begin() + joint_inds.size(), T, affinedofs, rotationaxis);
  }
  return out;
}

void RobotAndDOF::SetRobotActiveDOFs()  {
  RobotBasePtr robot1 = boost::dynamic_pointer_cast<RobotBase>(robot); // since robot is just a kinbody
  vector<int> current_active = robot1->GetActiveDOFIndices();
  if (robot1->GetActiveDOF() != GetDOF() || !std::equal(current_active.begin(), current_active.end(), joint_inds.begin()))
    robot1->SetActiveDOFs(joint_inds, affinedofs);
}

void RobotAndDOF::GetDOFLimits(DblVec& lower, DblVec& upper) const {
  if (joint_inds.size() > 0)
    robot->GetDOFLimits(lower, upper, joint_inds);
  const int translation_dofs[3] = {DOF_X, DOF_Y, DOF_Z};
  for (int i=0; i < 3; ++i) {
    if (affinedofs & translation_dofs[i]) {
      lower.push_back(-INFINITY);
      upper.push_back(INFINITY);
    }
  }
  if (affinedofs & DOF_RotationMask) {
    if (affinedofs & DOF_RotationAxis) {
      lower.push_back(-INFINITY);
      upper.push_back(INFINITY);
    }
    else if (affinedofs & DOF_Rotation3D) {
      for (int i=0; i < 3; ++i) {
        lower.push_back(-INFINITY);
        upper.push_back(INFINITY);
      }
    }
    else if (affinedofs & DOF_Rotation3D) {
      for (int i=0; i < 3; ++i) {
        lower.push_back(-INFINITY);
        upper.push_back(INFINITY);
      }
    }
    else if (affinedofs & DOF_RotationQuat) {
      for (int i=0; i < 4; ++i) {
        lower.push_back(-1);
        upper.push_back(1);
      }
    }
    else throw OR::openrave_exception("invalid rotation dofs", ORE_InvalidArguments);
  }
}
int RobotAndDOF::GetDOF() const {
  return joint_inds.size() + RaveGetAffineDOF(affinedofs);
}
DblMatrix RobotAndDOF::PositionJacobian(int link_ind, const OR::Vector& pt) const {
  Configuration::SaverPtr saver = const_cast<RobotAndDOF*>(this)->Save();
  const_cast<RobotAndDOF*>(this)->SetRobotActiveDOFs();
  vector<double> jacdata;
  boost::dynamic_pointer_cast<RobotBase>(robot)->CalculateActiveJacobian(link_ind, pt, jacdata);
  return Eigen::Map<DblMatrix>(jacdata.data(), 3, GetDOF());
}
DblMatrix RobotAndDOF::RotationJacobian(int link_ind) const {
  Configuration::SaverPtr saver = const_cast<RobotAndDOF*>(this)->Save();
  const_cast<RobotAndDOF*>(this)->SetRobotActiveDOFs();
  vector<double> jacdata;
  boost::dynamic_pointer_cast<RobotBase>(robot)->ComputeJacobianAxisAngle(link_ind, jacdata);
  return Eigen::Map<DblMatrix>(jacdata.data(), 3, GetDOF());
}
bool RobotAndDOF::DoesAffect(const KinBody::Link& link) {
  if (affinedofs > 0) return true;
  else if (link.GetParent() == GetRobot()) return trajopt::DoesAffect(*GetRobot(), joint_inds, GetRobotLinkIndex(*GetRobot(), link));
  else return false;
}

std::vector<KinBody::LinkPtr> RobotAndDOF::GetAffectedLinks() {
  vector<int> inds;
  std::vector<KinBody::LinkPtr> out;
  GetAffectedLinks(out,false,inds);
  return out;
}

void RobotAndDOF::GetAffectedLinks(std::vector<KinBody::LinkPtr>& links, bool only_with_geom, vector<int>& link_inds) {
  links.clear();
  link_inds.clear();
  BOOST_FOREACH(const KinBody::LinkPtr& link, GetRobot()->GetLinks()) {
    if (this->DoesAffect(*link) && !(only_with_geom && link->GetGeometries().empty())) {
      links.push_back(link);
      link_inds.push_back(link->GetIndex());
    }
  }

  vector<KinBodyPtr> grabbed;
  boost::dynamic_pointer_cast<RobotBase>(robot)->GetGrabbed(grabbed);
  BOOST_FOREACH(const KinBodyPtr& body, grabbed) {
    KinBody::LinkPtr grabberLink = boost::dynamic_pointer_cast<RobotBase>(robot)->IsGrabbing(body);
    assert(grabberLink);
    BOOST_FOREACH(const KinBody::LinkPtr& link, body->GetLinks()) {
      if (link->GetGeometries().size() > 0) {
        links.push_back(link);
        link_inds.push_back(grabberLink->GetIndex());
      }
    }
  }

}

vector<KinBodyPtr> RobotAndDOF::GetBodies() {
  std::set<KinBodyPtr> bodies;
  robot->GetAttached(bodies);
  return vector<KinBodyPtr> (bodies.begin(), bodies.end());
}

DblVec RobotAndDOF::RandomDOFValues() {
  int ndof = GetDOF();
  DblVec lower, upper;
  GetDOFLimits(lower, upper);
  DblVec out(ndof);
  for (int i=0; i < ndof; ++i) {
    // TODO this is only right for a circular joint!!
    lower[i] = fmax(lower[i], -2*M_PI);
    upper[i] = fmin(upper[i], 2*M_PI);
    out[i] = lower[i] + randf() * (upper[i] - lower[i]);
  }
  return out;
}

}
<|endoftext|>