<commit_before>#ifdef _WIN32
#   define NOMINMAX
#endif

#include "dsb/comm.hpp"

#include <algorithm>
#include <cassert>
#include <cstring>

#include "dsb/config.h"
#include "dsb/error.hpp"
#include "dsb/util.hpp"

namespace
{
    void SendFrames(
        zmq::socket_t& socket,
        std::deque<zmq::message_t>& message,
        bool moreComing)
    {
        assert (!message.empty());
        for (auto it = message.begin(); ; ) {
            auto m = it++;
            if (it == message.end()) {
                if (moreComing) socket.send(*m, ZMQ_SNDMORE);
                else            socket.send(*m);
                break;
            } else {
                socket.send(*m, ZMQ_SNDMORE);
            }
        }
        message.clear();
    }
}

void dsb::comm::Send(zmq::socket_t& socket, std::deque<zmq::message_t>& message)
{
    DSB_INPUT_CHECK(!message.empty());
    SendFrames(socket, message, false);
    assert (message.empty());
}

void dsb::comm::AddressedSend(
    zmq::socket_t& socket,
    std::deque<zmq::message_t>& envelope,
    std::deque<zmq::message_t>& body)
{
    DSB_INPUT_CHECK(!envelope.empty());
    DSB_INPUT_CHECK(!body.empty());
    SendFrames(socket, envelope, true);
    socket.send("", 0, ZMQ_SNDMORE);
    SendFrames(socket, body, false);
    assert (envelope.empty());
    assert (body.empty());
}

void dsb::comm::Receive(
    zmq::socket_t& socket,
    std::deque<zmq::message_t>& message)
{
    message.clear();
    do {
#if DSB_USE_MSVC_EMPLACE_WORKAROUND
        message.emplace_back(zmq::message_t());
#else
        message.emplace_back();
#endif
        socket.recv(&message.back());
    } while (message.back().more());
}

bool dsb::comm::Receive(
    zmq::socket_t& socket,
    std::deque<zmq::message_t>& message,
    boost::chrono::milliseconds timeout)
{
    zmq::pollitem_t pollItem = { socket, 0, ZMQ_POLLIN, 0 };
    if (zmq::poll(&pollItem, 1, static_cast<long>(timeout.count())) == 0) {
        return false;
    } else {
        assert (pollItem.revents == ZMQ_POLLIN);
        dsb::comm::Receive(socket, message);
        return true;
    }
}

size_t dsb::comm::PopMessageEnvelope(
    std::deque<zmq::message_t>& message,
    std::deque<zmq::message_t>* envelope)
{
    auto delim = std::find_if(message.begin(), message.end(),
                              [](const zmq::message_t& m) { return m.size() == 0; });
    if (delim == message.end()) {
        if (envelope) envelope->clear();
        return 0;
    }
    const auto envSize = delim - message.begin();
    if (envelope) {
        envelope->resize(envSize);
        std::move(message.begin(), delim, envelope->begin());
    }
    message.erase(message.begin(), ++delim);
    return envSize + 1;
}

void dsb::comm::CopyMessage(
    std::deque<zmq::message_t>& source,
    std::deque<zmq::message_t>& target)
{
    target.resize(source.size());
    for (size_t i = 0; i < source.size(); ++i) {
        target[i].copy(&source[i]);
    }
}

void dsb::comm::CopyMessage(
    const std::deque<zmq::message_t>& source,
    std::deque<zmq::message_t>& target)
{
    target.clear();
    for (auto it = source.cbegin(); it != source.cend(); ++it) {
        target.push_back(zmq::message_t(it->size()));
        std::memcpy(target.back().data(), it->data(), it->size());
    }
}

std::string dsb::comm::ToString(const zmq::message_t& frame)
{
    return std::string(static_cast<const char*>(frame.data()), frame.size());
}

zmq::message_t dsb::comm::ToFrame(const std::string& s)
{
    auto msg = zmq::message_t(s.size());
    std::memcpy(msg.data(), s.data(), s.size());
    return msg;
}

std::string dsb::comm::LastEndpoint(zmq::socket_t& socket)
{
    const size_t MAX_ENDPOINT_SIZE = 257; // including terminating zero
    char buffer[MAX_ENDPOINT_SIZE];
    size_t length = MAX_ENDPOINT_SIZE;
    socket.getsockopt(ZMQ_LAST_ENDPOINT, buffer, &length);
    assert (length > 0 && buffer[length-1] == '\0');
    return std::string(buffer, length-1);
}

namespace dsb { namespace comm {

Reactor::Reactor()
    : m_nextTimerID(0),
      m_needsRebuild(false),
      m_continuePolling(false)
{ }

void Reactor::AddSocket(zmq::socket_t& socket, SocketHandler handler)
{
    m_sockets.push_back(std::make_pair(&socket, handler));
    m_needsRebuild = true;
}

void Reactor::RemoveSocket(zmq::socket_t& socket)
{
    // Actual removal is deferred to the next rebuild.  At this stage, we just
    // replace the socket pointer with null.
    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it) {
        if (it->first == &socket) it->first = nullptr;
    }
    m_needsRebuild = true;
}

namespace
{
    // We use templates to work around the fact that Reactor::Timer is private.
    template<typename T>
    bool EventTimeGreater(const T& a, const T& b)
    {
        return a.nextEventTime > b.nextEventTime;
    }

    template<typename T>
    void PushTimer(std::vector<T>& v, const T& t)
    {
        v.push_back(t);
        std::push_heap(std::begin(v), std::end(v), EventTimeGreater<T>);
    }

    template<typename T>
    void PopTimer(std::vector<T>& v)
    {
        std::pop_heap(std::begin(v), std::end(v), EventTimeGreater<T>);
        v.pop_back();
    }
}

int Reactor::AddTimer(
    boost::chrono::milliseconds interval,
    int count,
    TimerHandler handler)
{
    if (interval < boost::chrono::milliseconds(0)) {
        throw std::invalid_argument("Negative interval");
    }
    if (count == 0) {
        throw std::invalid_argument("Invalid timer count");
    }
    Timer t = {
        ++m_nextTimerID,
        boost::chrono::system_clock::now() + interval,
        interval,
        count,
        handler
    };
    PushTimer(m_timers, t);
    return t.id;
}

void Reactor::RemoveTimer(int id)
{
    const auto it = std::find_if(m_timers.begin(), m_timers.end(),
        [id](const Timer& t){ return t.id == id; });
    if (it == m_timers.end()) {
        throw std::invalid_argument("Invalid timer ID");
    }
    m_timers.erase(it);
    std::make_heap(std::begin(m_timers), std::end(m_timers), &EventTimeGreater<Timer>);
}

void Reactor::Run()
{
    m_continuePolling = true;
    do {
        if (m_needsRebuild) Rebuild();
        zmq::poll(m_pollItems.data(), m_pollItems.size(),
                  m_timers.empty() ? -1 : static_cast<long>(TimeToNextEvent().count()));
        for (size_t i = 0; i < m_pollItems.size(); ++i) {
            if ((m_pollItems[i].revents & ZMQ_POLLIN) && m_sockets[i].first != nullptr) {
                m_sockets[i].second(*this, *m_sockets[i].first);
            }
        }
        while (!m_timers.empty()
               && boost::chrono::system_clock::now() >= m_timers.front().nextEventTime) {
            PerformNextEvent();
        }
    } while (m_continuePolling);
}

void Reactor::Stop()
{
    m_continuePolling = false;
}

boost::chrono::milliseconds Reactor::TimeToNextEvent() const
{
    return std::max(
        boost::chrono::duration_cast<boost::chrono::milliseconds>(
            m_timers.front().nextEventTime - boost::chrono::system_clock::now()),
        boost::chrono::milliseconds(0));
}

void Reactor::PerformNextEvent()
{
    auto t = m_timers.front();
    assert (t.nextEventTime <= boost::chrono::system_clock::now());
    assert (t.remaining != 0);

    // We need to update the timer queue even if the handler throws.
    auto updateTimer = dsb::util::OnScopeExit([&] () {
        // Timer may already have been removed by handler,
        // in which case we do nothing.
        if (m_timers.front().id == t.id) {
            PopTimer(m_timers);
            if (t.remaining > 0) --t.remaining;
            if (t.remaining != 0) {
                t.nextEventTime = boost::chrono::system_clock::now() + t.interval;
                PushTimer(m_timers, t);
            }
        }
    });
    t.handler(*this, t.id);
}

void Reactor::Rebuild()
{
    // Remove null sockets from m_sockets
    auto newEnd = std::remove_if(m_sockets.begin(), m_sockets.end(),
        [](const SocketHandlerPair& a) { return a.first == nullptr; });
    m_sockets.erase(newEnd, m_sockets.end());

    // Rebuild m_pollItems
    m_pollItems.clear();
    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it) {
        zmq::pollitem_t pi = { *it->first, 0, ZMQ_POLLIN, 0 };
        m_pollItems.push_back(pi);
    }
    m_needsRebuild = false;
}

}} // namespace
<commit_msg>Fixed "next event time" calculation<commit_after>#ifdef _WIN32
#   define NOMINMAX
#endif

#include "dsb/comm.hpp"

#include <algorithm>
#include <cassert>
#include <cstring>

#include "dsb/config.h"
#include "dsb/error.hpp"
#include "dsb/util.hpp"

namespace
{
    void SendFrames(
        zmq::socket_t& socket,
        std::deque<zmq::message_t>& message,
        bool moreComing)
    {
        assert (!message.empty());
        for (auto it = message.begin(); ; ) {
            auto m = it++;
            if (it == message.end()) {
                if (moreComing) socket.send(*m, ZMQ_SNDMORE);
                else            socket.send(*m);
                break;
            } else {
                socket.send(*m, ZMQ_SNDMORE);
            }
        }
        message.clear();
    }
}

void dsb::comm::Send(zmq::socket_t& socket, std::deque<zmq::message_t>& message)
{
    DSB_INPUT_CHECK(!message.empty());
    SendFrames(socket, message, false);
    assert (message.empty());
}

void dsb::comm::AddressedSend(
    zmq::socket_t& socket,
    std::deque<zmq::message_t>& envelope,
    std::deque<zmq::message_t>& body)
{
    DSB_INPUT_CHECK(!envelope.empty());
    DSB_INPUT_CHECK(!body.empty());
    SendFrames(socket, envelope, true);
    socket.send("", 0, ZMQ_SNDMORE);
    SendFrames(socket, body, false);
    assert (envelope.empty());
    assert (body.empty());
}

void dsb::comm::Receive(
    zmq::socket_t& socket,
    std::deque<zmq::message_t>& message)
{
    message.clear();
    do {
#if DSB_USE_MSVC_EMPLACE_WORKAROUND
        message.emplace_back(zmq::message_t());
#else
        message.emplace_back();
#endif
        socket.recv(&message.back());
    } while (message.back().more());
}

bool dsb::comm::Receive(
    zmq::socket_t& socket,
    std::deque<zmq::message_t>& message,
    boost::chrono::milliseconds timeout)
{
    zmq::pollitem_t pollItem = { socket, 0, ZMQ_POLLIN, 0 };
    if (zmq::poll(&pollItem, 1, static_cast<long>(timeout.count())) == 0) {
        return false;
    } else {
        assert (pollItem.revents == ZMQ_POLLIN);
        dsb::comm::Receive(socket, message);
        return true;
    }
}

size_t dsb::comm::PopMessageEnvelope(
    std::deque<zmq::message_t>& message,
    std::deque<zmq::message_t>* envelope)
{
    auto delim = std::find_if(message.begin(), message.end(),
                              [](const zmq::message_t& m) { return m.size() == 0; });
    if (delim == message.end()) {
        if (envelope) envelope->clear();
        return 0;
    }
    const auto envSize = delim - message.begin();
    if (envelope) {
        envelope->resize(envSize);
        std::move(message.begin(), delim, envelope->begin());
    }
    message.erase(message.begin(), ++delim);
    return envSize + 1;
}

void dsb::comm::CopyMessage(
    std::deque<zmq::message_t>& source,
    std::deque<zmq::message_t>& target)
{
    target.resize(source.size());
    for (size_t i = 0; i < source.size(); ++i) {
        target[i].copy(&source[i]);
    }
}

void dsb::comm::CopyMessage(
    const std::deque<zmq::message_t>& source,
    std::deque<zmq::message_t>& target)
{
    target.clear();
    for (auto it = source.cbegin(); it != source.cend(); ++it) {
        target.push_back(zmq::message_t(it->size()));
        std::memcpy(target.back().data(), it->data(), it->size());
    }
}

std::string dsb::comm::ToString(const zmq::message_t& frame)
{
    return std::string(static_cast<const char*>(frame.data()), frame.size());
}

zmq::message_t dsb::comm::ToFrame(const std::string& s)
{
    auto msg = zmq::message_t(s.size());
    std::memcpy(msg.data(), s.data(), s.size());
    return msg;
}

std::string dsb::comm::LastEndpoint(zmq::socket_t& socket)
{
    const size_t MAX_ENDPOINT_SIZE = 257; // including terminating zero
    char buffer[MAX_ENDPOINT_SIZE];
    size_t length = MAX_ENDPOINT_SIZE;
    socket.getsockopt(ZMQ_LAST_ENDPOINT, buffer, &length);
    assert (length > 0 && buffer[length-1] == '\0');
    return std::string(buffer, length-1);
}

namespace dsb { namespace comm {

Reactor::Reactor()
    : m_nextTimerID(0),
      m_needsRebuild(false),
      m_continuePolling(false)
{ }

void Reactor::AddSocket(zmq::socket_t& socket, SocketHandler handler)
{
    m_sockets.push_back(std::make_pair(&socket, handler));
    m_needsRebuild = true;
}

void Reactor::RemoveSocket(zmq::socket_t& socket)
{
    // Actual removal is deferred to the next rebuild.  At this stage, we just
    // replace the socket pointer with null.
    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it) {
        if (it->first == &socket) it->first = nullptr;
    }
    m_needsRebuild = true;
}

namespace
{
    // We use templates to work around the fact that Reactor::Timer is private.
    template<typename T>
    bool EventTimeGreater(const T& a, const T& b)
    {
        return a.nextEventTime > b.nextEventTime;
    }

    template<typename T>
    void PushTimer(std::vector<T>& v, const T& t)
    {
        v.push_back(t);
        std::push_heap(std::begin(v), std::end(v), EventTimeGreater<T>);
    }

    template<typename T>
    void PopTimer(std::vector<T>& v)
    {
        std::pop_heap(std::begin(v), std::end(v), EventTimeGreater<T>);
        v.pop_back();
    }
}

int Reactor::AddTimer(
    boost::chrono::milliseconds interval,
    int count,
    TimerHandler handler)
{
    if (interval < boost::chrono::milliseconds(0)) {
        throw std::invalid_argument("Negative interval");
    }
    if (count == 0) {
        throw std::invalid_argument("Invalid timer count");
    }
    Timer t = {
        ++m_nextTimerID,
        boost::chrono::system_clock::now() + interval,
        interval,
        count,
        handler
    };
    PushTimer(m_timers, t);
    return t.id;
}

void Reactor::RemoveTimer(int id)
{
    const auto it = std::find_if(m_timers.begin(), m_timers.end(),
        [id](const Timer& t){ return t.id == id; });
    if (it == m_timers.end()) {
        throw std::invalid_argument("Invalid timer ID");
    }
    m_timers.erase(it);
    std::make_heap(std::begin(m_timers), std::end(m_timers), &EventTimeGreater<Timer>);
}

void Reactor::Run()
{
    m_continuePolling = true;
    do {
        if (m_needsRebuild) Rebuild();
        zmq::poll(m_pollItems.data(), m_pollItems.size(),
                  m_timers.empty() ? -1 : static_cast<long>(TimeToNextEvent().count()));
        for (size_t i = 0; i < m_pollItems.size(); ++i) {
            if ((m_pollItems[i].revents & ZMQ_POLLIN) && m_sockets[i].first != nullptr) {
                m_sockets[i].second(*this, *m_sockets[i].first);
            }
        }
        while (!m_timers.empty()
               && boost::chrono::system_clock::now() >= m_timers.front().nextEventTime) {
            PerformNextEvent();
        }
    } while (m_continuePolling);
}

void Reactor::Stop()
{
    m_continuePolling = false;
}

boost::chrono::milliseconds Reactor::TimeToNextEvent() const
{
    return std::max(
        boost::chrono::duration_cast<boost::chrono::milliseconds>(
            m_timers.front().nextEventTime - boost::chrono::system_clock::now()),
        boost::chrono::milliseconds(0));
}

void Reactor::PerformNextEvent()
{
    auto t = m_timers.front();
    assert (t.nextEventTime <= boost::chrono::system_clock::now());
    assert (t.remaining != 0);

    // We need to update the timer queue even if the handler throws.
    auto updateTimer = dsb::util::OnScopeExit([&] () {
        // Timer may already have been removed by handler,
        // in which case we do nothing.
        if (m_timers.front().id == t.id) {
            PopTimer(m_timers);
            if (t.remaining > 0) --t.remaining;
            if (t.remaining != 0) {
                t.nextEventTime += t.interval;
                PushTimer(m_timers, t);
            }
        }
    });
    t.handler(*this, t.id);
}

void Reactor::Rebuild()
{
    // Remove null sockets from m_sockets
    auto newEnd = std::remove_if(m_sockets.begin(), m_sockets.end(),
        [](const SocketHandlerPair& a) { return a.first == nullptr; });
    m_sockets.erase(newEnd, m_sockets.end());

    // Rebuild m_pollItems
    m_pollItems.clear();
    for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it) {
        zmq::pollitem_t pi = { *it->first, 0, ZMQ_POLLIN, 0 };
        m_pollItems.push_back(pi);
    }
    m_needsRebuild = false;
}

}} // namespace
<|endoftext|>


<commit_before>#include <algorithm>
#include <fstream>

#include "CCameraController.h"

#include <GLFW/glfw3.h>
#include <json/json.h>

#include "debug/Log.h"

#include "graphics/camera/IControllableCamera.h"

#include "input/IInputProvider.h"
#include "io/JsonUtil.h"
#include "io/JsonDeserialize.h"

CCameraController::CCameraController() {}

CCameraController::~CCameraController()
{
    if (m_inputProvider != nullptr)
    {
        m_inputProvider->removeInputListener(this);
    }
}

void CCameraController::setCamera(std::shared_ptr<IControllableCamera> camera)
{
    m_camera = camera;
}

void CCameraController::setInputProvider(IInputProvider* provider)
{
    if (m_inputProvider != nullptr)
    {
        m_inputProvider->removeInputListener(this);
    }

    m_inputProvider = provider;

    if (m_inputProvider != nullptr)
    {
        m_inputProvider->addInputListener(this);
    }
}

bool CCameraController::loadSequence(std::string file)
{
    m_sequenceTime = 0;
    m_sequencePoints.clear();

    Json::Reader reader;
    Json::Value root;

    // Load scene file
    std::ifstream ifs(file);
    if (!ifs.is_open())
    {
        LOG_ERROR("Failed to open json file %s.", file.c_str());
        return false;
    }

    // Parse json data
    if (!reader.parse(ifs, root))
    {
        LOG_ERROR("Failed to load scene file %s with error %s.", file.c_str(),
                  reader.getFormattedErrorMessages().c_str());
        return false;
    }
    // Read done, close file
    ifs.close();

    Json::Value node = root["positions"];

    // Node empty?
    if (node.empty())
    {
        LOG_INFO("Missing or empty 'positions' node. No scene objects are loaded.");
        return true;
    }

    // Node is array type
    if (!node.isArray())
    {
        LOG_ERROR("The node 'positions' must be array type.");
        return false;
    }

    bool success = true;

    for (unsigned int i = 0; i < node.size(); ++i)
    {
        glm::vec3 position;
        glm::vec3 orientation;
        float timestamp;
        bool fxaaActive;
        bool fogActive;

        if (!load(node[i], "position", position))
        {
            LOG_ERROR("Failed loading node 'position' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "orientation", orientation))
        {
            LOG_ERROR("Failed loading node 'orientation' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "timestamp", timestamp))
        {
            LOG_ERROR("Failed loading node 'timestamp' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "fxaa", fxaaActive))
        {
            LOG_ERROR("Failed loading node 'fxaa' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "fog", fogActive))
        {
            LOG_ERROR("Failed loading node 'fog' for element #%i.", i);
            success = false;
            break;
        }

        SequencePoint sp{position, glm::normalize(orientation), timestamp, fxaaActive, fogActive};
        m_sequencePoints.push_back(sp);
    }

    m_isRunningSequence = success;
    return success;
}

void CCameraController::animate(float dt)
{
    if (m_inputProvider != nullptr && m_camera != nullptr)
    {
        animateFeatures(dt);

        if (m_isRunningSequence)
        {
            animateSequence(dt);
        }
        else
        {
            animateManual(dt);
        }
    }
}

void CCameraController::animateFeatures(float dt) {
    // tODO
}

void CCameraController::animateSequence(float dt) {
    if (m_inputProvider->isKeyPressed(GLFW_KEY_C))
    {
        m_isRunningSequence = false;
        return;
    }

    float timeModifier = 1.0f;
    if (m_inputProvider->isKeyPressed(GLFW_KEY_B))
    {
        timeModifier = -2.0f;
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_N))
    {
        timeModifier = 4.0f;
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_M))
    {
        timeModifier = 8.0f;
    }

    m_sequenceTime += (dt * timeModifier);

    if (m_sequenceTime > m_sequencePoints.back().timestamp)
    {
        m_isRunningSequence = false;
        return;
    }

    auto it = std::find_if(m_sequencePoints.begin(), m_sequencePoints.end(),
                           [&](const SequencePoint& s)
                           {
                               return s.timestamp >= m_sequenceTime;
                           });

    if (it == m_sequencePoints.begin())
    {
        // not started yet
        return;
    }

    SequencePoint after = *it;
    SequencePoint before = *(--it);

    float ix = (m_sequenceTime - before.timestamp) / (after.timestamp - before.timestamp);
    glm::vec3 cameraPosition = before.position * (1.0f - ix) + after.position * ix;
    glm::vec3 cameraOrientation = before.orientation * (1.0f - ix) + after.orientation * ix;

    m_camera->lookAt(cameraPosition, cameraPosition + cameraOrientation, glm::vec3(0,1,0));
    m_camera->getFeatureInfoForWrite().fogType = (before.fogActive ? FogType::Exp2 : FogType::None);
    m_camera->getFeatureInfoForWrite().fxaaActive = before.fxaaActive;
}

void CCameraController::animateManual(float dt) {
    float walkingModifier = 1.0f;
    if (m_inputProvider->isKeyPressed(GLFW_KEY_SPACE))
    {
        walkingModifier = 6.0f;
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_W))
    {
        m_camera->moveForward(dt * 2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_S))
    {
        m_camera->moveForward(dt * -2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_A))
    {
        m_camera->moveRight(dt * 2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_D))
    {
        m_camera->moveRight(dt * -2.f * m_speed * walkingModifier);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_Q))
    {
        m_camera->moveUp(dt * -2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_E))
    {
        m_camera->moveUp(dt * 2.f * m_speed * walkingModifier);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_UP))
    {
        m_camera->pitch(-dt * m_speed);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_DOWN))
    {
        m_camera->pitch(dt * m_speed);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_RIGHT))
    {
        m_camera->yaw(-dt * m_speed);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_LEFT))
    {
        m_camera->yaw(dt * m_speed);
    }
}

void CCameraController::handleKeyEvent(EKeyEventType type, int keyCode)
{
    if (type != EKeyEventType::KEY_PRESSED) {
        return;
    }

    SFeatureInfo& info = m_camera->getFeatureInfoForWrite();

	if (keyCode == GLFW_KEY_R)
	{
		switch (info.renderMode) {
		case RenderMode::Final:
			info.renderMode = RenderMode::Color;
			break;
		case RenderMode::Color:
			info.renderMode = RenderMode::Depth;
			break;
		case RenderMode::Depth:
			info.renderMode = RenderMode::Lights;
			break;
		case RenderMode::Lights:
			info.renderMode = RenderMode::Normals;
			break;
		case RenderMode::Normals:
			info.renderMode = RenderMode::GodRay;
			break;
		case RenderMode::GodRay:
			info.renderMode = RenderMode::Final;
			break;
		default:
			info.renderMode = RenderMode::Final;
			break;
		}
	}

    if (keyCode == GLFW_KEY_T)
    {
        switch (info.fogType) {
            case FogType::None:
                info.fogType = FogType::Linear;
                break;
            case FogType::Linear:
                info.fogType = FogType::Exp;
                break;
            case FogType::Exp:
                info.fogType = FogType::Exp2;
                break;
            case FogType::Exp2:
                info.fogType = FogType::None;
                break;
            default:
                info.fogType = FogType::None;
                break;
        }
    }

    if (keyCode == GLFW_KEY_Z)
    {
        info.shadowsActive = !info.shadowsActive;
    }

    if (keyCode == GLFW_KEY_U)
    {
        info.fxaaActive = !info.fxaaActive;
    }

    if (keyCode == GLFW_KEY_I)
    {
        info.dofActive = !info.dofActive;
    }

    if (keyCode == GLFW_KEY_O)
    {
        info.normalMappingActive = !info.normalMappingActive;
    }

	if (keyCode == GLFW_KEY_P)
	{
		info.godRayActive = !info.godRayActive;
	}
}

void CCameraController::handleMouseMovementEvent(int x, int y)
{
    m_camera->pitch((y - m_lastY) * m_speed / 1000);
    m_camera->yaw(-(x - m_lastX) * m_speed / 1000);

    m_lastX = x;
    m_lastY = y;
}

void CCameraController::handleMouseButtonEvent(EMouseButtonEventType type, int buttonCode)
{
    // TODO
}

void CCameraController::handleResizeEvent(int width, int height)
{
    m_camera->setProjection(m_camera->getFieldOfView(), (float)width / height, m_camera->getZNear(),
                            m_camera->getZFar());
}
<commit_msg>cleanup<commit_after>#include <algorithm>
#include <fstream>

#include "CCameraController.h"

#include <GLFW/glfw3.h>
#include <json/json.h>

#include "debug/Log.h"

#include "graphics/camera/IControllableCamera.h"

#include "input/IInputProvider.h"
#include "io/JsonUtil.h"
#include "io/JsonDeserialize.h"

CCameraController::CCameraController() {}

CCameraController::~CCameraController()
{
    if (m_inputProvider != nullptr)
    {
        m_inputProvider->removeInputListener(this);
    }
}

void CCameraController::setCamera(std::shared_ptr<IControllableCamera> camera)
{
    m_camera = camera;
}

void CCameraController::setInputProvider(IInputProvider* provider)
{
    if (m_inputProvider != nullptr)
    {
        m_inputProvider->removeInputListener(this);
    }

    m_inputProvider = provider;

    if (m_inputProvider != nullptr)
    {
        m_inputProvider->addInputListener(this);
    }
}

bool CCameraController::loadSequence(std::string file)
{
    m_sequenceTime = 0;
    m_sequencePoints.clear();

    Json::Reader reader;
    Json::Value root;

    // Load scene file
    std::ifstream ifs(file);
    if (!ifs.is_open())
    {
        LOG_ERROR("Failed to open json file %s.", file.c_str());
        return false;
    }

    // Parse json data
    if (!reader.parse(ifs, root))
    {
        LOG_ERROR("Failed to load scene file %s with error %s.", file.c_str(),
                  reader.getFormattedErrorMessages().c_str());
        return false;
    }
    // Read done, close file
    ifs.close();

    Json::Value node = root["positions"];

    // Node empty?
    if (node.empty())
    {
        LOG_INFO("Missing or empty 'positions' node. No scene objects are loaded.");
        return true;
    }

    // Node is array type
    if (!node.isArray())
    {
        LOG_ERROR("The node 'positions' must be array type.");
        return false;
    }

    bool success = true;

    for (unsigned int i = 0; i < node.size(); ++i)
    {
        glm::vec3 position;
        glm::vec3 orientation;
        float timestamp;
        bool fxaaActive;
        bool fogActive;

        if (!load(node[i], "position", position))
        {
            LOG_ERROR("Failed loading node 'position' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "orientation", orientation))
        {
            LOG_ERROR("Failed loading node 'orientation' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "timestamp", timestamp))
        {
            LOG_ERROR("Failed loading node 'timestamp' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "fxaa", fxaaActive))
        {
            LOG_ERROR("Failed loading node 'fxaa' for element #%i.", i);
            success = false;
            break;
        }

        if (!load(node[i], "fog", fogActive))
        {
            LOG_ERROR("Failed loading node 'fog' for element #%i.", i);
            success = false;
            break;
        }

        SequencePoint sp{position, glm::normalize(orientation), timestamp, fxaaActive, fogActive};
        m_sequencePoints.push_back(sp);
    }

    m_isRunningSequence = success;
    return success;
}

void CCameraController::animate(float dt)
{
    if (m_inputProvider != nullptr && m_camera != nullptr)
    {
        animateFeatures(dt);

        if (m_isRunningSequence)
        {
            animateSequence(dt);
        }
        else
        {
            animateManual(dt);
        }
    }
}

void CCameraController::animateFeatures(float dt) {
    // tODO
}

void CCameraController::animateSequence(float dt) {
    if (m_inputProvider->isKeyPressed(GLFW_KEY_C))
    {
        m_isRunningSequence = false;
        return;
    }

    float timeModifier = 1.0f;
    if (m_inputProvider->isKeyPressed(GLFW_KEY_B))
    {
        timeModifier = -2.0f;
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_N))
    {
        timeModifier = 4.0f;
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_M))
    {
        timeModifier = 8.0f;
    }

    m_sequenceTime += (dt * timeModifier);

    if (m_sequenceTime > m_sequencePoints.back().timestamp)
    {
        m_isRunningSequence = false;
        return;
    }

    auto it = std::find_if(m_sequencePoints.begin(), m_sequencePoints.end(),
                           [&](const SequencePoint& s)
                           {
                               return s.timestamp >= m_sequenceTime;
                           });

    if (it == m_sequencePoints.begin())
    {
        // not started yet
        return;
    }

    SequencePoint after = *it;
    SequencePoint before = *(--it);

    float ix = (m_sequenceTime - before.timestamp) / (after.timestamp - before.timestamp);
    glm::vec3 cameraPosition = before.position * (1.0f - ix) + after.position * ix;
    glm::vec3 cameraOrientation = before.orientation * (1.0f - ix) + after.orientation * ix;

    m_camera->lookAt(cameraPosition, cameraPosition + cameraOrientation, glm::vec3(0,1,0));
    m_camera->getFeatureInfoForWrite().fogType = (before.fogActive ? FogType::Exp2 : FogType::None);
    m_camera->getFeatureInfoForWrite().fxaaActive = before.fxaaActive;
}

void CCameraController::animateManual(float dt) {
    float walkingModifier = 1.0f;
    if (m_inputProvider->isKeyPressed(GLFW_KEY_SPACE))
    {
        walkingModifier = 6.0f;
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_W))
    {
        m_camera->moveForward(dt * 2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_S))
    {
        m_camera->moveForward(dt * -2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_A))
    {
        m_camera->moveRight(dt * 2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_D))
    {
        m_camera->moveRight(dt * -2.f * m_speed * walkingModifier);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_Q))
    {
        m_camera->moveUp(dt * -2.f * m_speed * walkingModifier);
    }
    if (m_inputProvider->isKeyPressed(GLFW_KEY_E))
    {
        m_camera->moveUp(dt * 2.f * m_speed * walkingModifier);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_UP))
    {
        m_camera->pitch(-dt * m_speed);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_DOWN))
    {
        m_camera->pitch(dt * m_speed);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_RIGHT))
    {
        m_camera->yaw(-dt * m_speed);
    }

    if (m_inputProvider->isKeyPressed(GLFW_KEY_LEFT))
    {
        m_camera->yaw(dt * m_speed);
    }
}

void CCameraController::handleKeyEvent(EKeyEventType type, int keyCode)
{
    if (type != EKeyEventType::KEY_PRESSED) {
        return;
    }

    SFeatureInfo& info = m_camera->getFeatureInfoForWrite();

	if (keyCode == GLFW_KEY_R)
	{
		switch (info.renderMode) {
		case RenderMode::Final:
			info.renderMode = RenderMode::Color;
			break;
		case RenderMode::Color:
			info.renderMode = RenderMode::Depth;
			break;
		case RenderMode::Depth:
			info.renderMode = RenderMode::Lights;
			break;
		case RenderMode::Lights:
			info.renderMode = RenderMode::Normals;
			break;
		case RenderMode::Normals:
			info.renderMode = RenderMode::GodRay;
			break;
		case RenderMode::GodRay:
			info.renderMode = RenderMode::Final;
			break;
		default:
			info.renderMode = RenderMode::Final;
			break;
		}
	}

    if (keyCode == GLFW_KEY_T)
    {
        switch (info.fogType) {
            case FogType::None:
                info.fogType = FogType::Linear;
                break;
            case FogType::Linear:
                info.fogType = FogType::Exp;
                break;
            case FogType::Exp:
                info.fogType = FogType::Exp2;
                break;
            case FogType::Exp2:
                info.fogType = FogType::None;
                break;
            default:
                info.fogType = FogType::None;
                break;
        }
    }

    if (keyCode == GLFW_KEY_Z)
    {
        info.shadowsActive = !info.shadowsActive;
    }

    if (keyCode == GLFW_KEY_U)
    {
        info.fxaaActive = !info.fxaaActive;
    }

    if (keyCode == GLFW_KEY_I)
    {
        info.dofActive = !info.dofActive;
    }

    if (keyCode == GLFW_KEY_O)
    {
        info.normalMappingActive = !info.normalMappingActive;
    }

	if (keyCode == GLFW_KEY_P)
	{
		info.godRayActive = !info.godRayActive;
	}
}

void CCameraController::handleMouseMovementEvent(int x, int y)
{
    m_camera->pitch((y - m_lastY) * m_speed / 1000);
    m_camera->yaw(-(x - m_lastX) * m_speed / 1000);

    m_lastX = x;
    m_lastY = y;
}

void CCameraController::handleMouseButtonEvent(EMouseButtonEventType type, int buttonCode)
{
    // TODO
}

void CCameraController::handleResizeEvent(int width, int height)
{
    m_camera->setProjection(m_camera->getFieldOfView(), (float)width / height, m_camera->getZNear(), m_camera->getZFar());
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include "Storage.h"

namespace fblualib {
namespace python {

int initStorage(lua_State* L) {
  PythonGuard g;
  PythonStorage<double>::define();
  PythonStorage<float>::define();
  PythonStorage<int>::define();
  PythonStorage<long>::define();
  PythonStorage<unsigned char>::define();
  return 0;
}

}}  // namespaces
<commit_msg>comment out unused parameter in python/Storage.cpp<commit_after>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include "Storage.h"

namespace fblualib {
namespace python {

int initStorage(lua_State* /*L*/) {
  PythonGuard g;
  PythonStorage<double>::define();
  PythonStorage<float>::define();
  PythonStorage<int>::define();
  PythonStorage<long>::define();
  PythonStorage<unsigned char>::define();
  return 0;
}

}}  // namespaces
<|endoftext|>


<commit_before><commit_msg>Attempting to resolve AI over-spawn issue - I believe players transferring to another server would result in the server entering sleep immediately and not resolving to remove the player ship somehow, resulting in ever-increasing maxPlayerScoreAI() returns. Resulted to calculating actual connected clients.<commit_after><|endoftext|>


<commit_before>#include "outputfunction.h"

spnp::OutputFunction::OutputFunction(OutputFunction::TYPE type, std::string objId, std::string option)
    :AbstractData()
{
    this->objId = objId;
    this->option = option;
    this->type = type;
    this->functionNumber = 0;

    this->vars = "";
    this->functionName = "";
    this->functionString = "";
    this->finalString = "";
    this->descriptionString = "";

    this->prepareData();
}

spnp::OutputFunction::~OutputFunction()
{

}

XMLNode *spnp::OutputFunction::toXML()
{
    XMLNode* n = AbstractData::toXML();
    n->setAttribute("object_id", this->objId);
    n->setAttribute("option", this->option);
    n->setAttribute("type",static_cast<int>(this->type));

    return n;
}

void spnp::OutputFunction::fromXML(XMLNode *xml)
{
    AbstractData::fromXML(xml);
    this->objId = xml->getAttributeS("object_id");
    this->option = xml->getAttributeS("option");
    this->type = static_cast<OutputFunction::TYPE>(xml->getAttributeI("type"));
}

void spnp::OutputFunction::setFunctionNumber(int num)
{
    this->functionNumber = num;
}

std::string spnp::OutputFunction::c_str(spnp::IData *data) const
{
    (void)data;

    return "";
}

std::string spnp::OutputFunction::getVariables()
{
    return this->vars;
}

std::string spnp::OutputFunction::getFunction()
{
    return this->functionString;
}

std::string spnp::OutputFunction::getFinal()
{
    return this->finalString;
}

std::string spnp::OutputFunction::getDescription()
{
    return this->descriptionString;
}

void spnp::OutputFunction::prepareFunction()
{
    switch (this->type)
    {
    case TYPE::EXPECTED_TOKEN_PLACE_STEADY:
        this->prepareETPS();
        break;
    case TYPE::EXPECTED_TOKEN_PLACE_TIME:
        this->prepareETPT();
        break;
    case TYPE::EXPECTED_TOKEN_PLACES_STEADY:
        this->prepareETPsS();
        break;
    case TYPE::EXPECTED_TOKEN_PLACES_TIME:
        this->prepareETPsT();
        break;

    case TYPE::THROUGHPUT_TRANSITION_STEADY:
        this->prepareTTS();
        break;
    case TYPE::THROUGHPUT_TRANSITION_TIME:
        this->prepareTTT();
        break;
    case TYPE::THROUGHPUT_TRANSITIONS_STEADY:
        this->prepareTTsS();
        break;
    case TYPE::THROUGHPUT_TRANSITIONS_TIME:
        this->prepareTTsT();
        break;

    case TYPE::UTILIZATION_TRANSITION_STEADY:
        this->prepareUTS();
        break;
    case TYPE::UTILIZATION_TRANSITION_TIME:
        this->prepareUTT();
        break;
    case TYPE::UTILIZATION_TRANSITIONS_STEADY:
        this->prepareUTsS();
        break;
    case TYPE::UTILIZATION_TRANSITIONS_TIME:
        this->prepareUTsT();
        break;

    case TYPE::PROB_PLACE_STEADY:
        this->preparePPS();
        break;
    case TYPE::PROB_PLACE_TIME:
        this->preparePPT();
        break;
    case TYPE::PROB_PLACES_STEADY:
        this->preparePPsS();
        break;
    case TYPE::PROB_PLACES_TIME:
        this->preparePPsT();
        break;

    case TYPE::EXPECTED_REWARD_STEADY:
        this->prepareERS();
        break;
    case TYPE::EXPECTED_REWARD_TIME:
        this->prepareERT();
        break;
    case TYPE::EXPECTED_ACCUMULATED_ABSORTION:
        this->prepareEAA();
        break;
    case TYPE::EXPECTED_ACCUMULATED_TIME:
        this->prepareEAT();
        break;
    case TYPE::STEADY_DEFAULT:
        this->prepareSD();
        break;
    case TYPE::VARIABLE:
        this->prepareV();
        break;
    default:
        this->prepareNull();
        break;
    }
}

std::string spnp::OutputFunction::getClassNodeName()
{
    return "output_funcion";
}

void spnp::OutputFunction::prepareData()
{
    this->functionName = "outFunc" + std::to_string(this->functionNumber);
    this->prepareFunction();
}

void spnp::OutputFunction::prepareETPS()
{
    this->functionString = "double " + this->functionName + "() {\n";
    this->functionString+= "\treturn(mark("+ objId +"));\n}\n";

    this->descriptionString = "Expected # of tokens of the place " + objId + " in steady-state";

    this->finalString = "\tsolve(INFINITY);\n";
    this->finalString += "pr_expected(\""+ this->descriptionString +"\","+ this->functionName +")";
}

void spnp::OutputFunction::prepareETPT()
{
    this->functionString = "double " + this->functionName + "() {\n";
    this->functionString+= "\treturn(mark("+ objId +"));\n}\n";

    this->descriptionString = "Expected # of tokens of the place " + objId + ": " + this->option;

    std::vector<std::string> data = this->split(this->option);
    this->finalString = "for(loop=" + data.at(0)+";loop<"+data.at(1)+";loop+="+data.at(2)+") {\n";
    this->finalString += "\tsolve((double) loop);\n";
    this->finalString += "\tpr_expected(\"Expected # of tokens of the place "+objId+"\","+this->functionName+");";
}

void spnp::OutputFunction::prepareETPsS()
{

}

void spnp::OutputFunction::prepareETPsT()
{

}

void spnp::OutputFunction::prepareTTS()
{

}

void spnp::OutputFunction::prepareTTT()
{

}

void spnp::OutputFunction::prepareTTsS()
{

}

void spnp::OutputFunction::prepareTTsT()
{

}

void spnp::OutputFunction::prepareUTS()
{

}

void spnp::OutputFunction::prepareUTT()
{

}

void spnp::OutputFunction::prepareUTsS()
{

}

void spnp::OutputFunction::prepareUTsT()
{

}

void spnp::OutputFunction::preparePPS()
{

}

void spnp::OutputFunction::preparePPT()
{

}

void spnp::OutputFunction::preparePPsS()
{

}

void spnp::OutputFunction::preparePPsT()
{

}

void spnp::OutputFunction::prepareERS()
{

}

void spnp::OutputFunction::prepareERT()
{

}

void spnp::OutputFunction::prepareEAA()
{

}

void spnp::OutputFunction::prepareEAT()
{

}

void spnp::OutputFunction::prepareSD()
{

}

void spnp::OutputFunction::prepareV()
{

}

void spnp::OutputFunction::prepareNull()
{

}

std::vector<std::string> spnp::OutputFunction::split(std::string in)
{
    std::vector<std::string> out;
    int index = -1;
    do
    {
        index = in.find(',');
        if(index>-1)
        {
            out.push_back(in.substr(0, index));
            in = in.substr(index, in.size());
        }
    } while(index > -1);

    return out;
}
<commit_msg>Correção na função de avaliação<commit_after>#include "outputfunction.h"

spnp::OutputFunction::OutputFunction(OutputFunction::TYPE type, std::string objId, std::string option)
    :AbstractData()
{
    this->objId = objId;
    this->option = option;
    this->type = type;
    this->functionNumber = 0;

    this->vars = "";
    this->functionName = "";
    this->functionString = "";
    this->finalString = "";
    this->descriptionString = "";

    this->prepareData();
}

spnp::OutputFunction::~OutputFunction()
{

}

XMLNode *spnp::OutputFunction::toXML()
{
    XMLNode* n = AbstractData::toXML();
    n->setAttribute("object_id", this->objId);
    n->setAttribute("option", this->option);
    n->setAttribute("type",static_cast<int>(this->type));

    return n;
}

void spnp::OutputFunction::fromXML(XMLNode *xml)
{
    AbstractData::fromXML(xml);
    this->objId = xml->getAttributeS("object_id");
    this->option = xml->getAttributeS("option");
    this->type = static_cast<OutputFunction::TYPE>(xml->getAttributeI("type"));
}

void spnp::OutputFunction::setFunctionNumber(int num)
{
    this->functionNumber = num;
}

std::string spnp::OutputFunction::c_str(spnp::IData *data) const
{
    (void)data;

    return "";
}

std::string spnp::OutputFunction::getVariables()
{
    return this->vars;
}

std::string spnp::OutputFunction::getFunction()
{
    return this->functionString;
}

std::string spnp::OutputFunction::getFinal()
{
    return this->finalString;
}

std::string spnp::OutputFunction::getDescription()
{
    return this->descriptionString;
}

void spnp::OutputFunction::prepareFunction()
{
    switch (this->type)
    {
    case TYPE::EXPECTED_TOKEN_PLACE_STEADY:
        this->prepareETPS();
        break;
    case TYPE::EXPECTED_TOKEN_PLACE_TIME:
        this->prepareETPT();
        break;
    case TYPE::EXPECTED_TOKEN_PLACES_STEADY:
        this->prepareETPsS();
        break;
    case TYPE::EXPECTED_TOKEN_PLACES_TIME:
        this->prepareETPsT();
        break;

    case TYPE::THROUGHPUT_TRANSITION_STEADY:
        this->prepareTTS();
        break;
    case TYPE::THROUGHPUT_TRANSITION_TIME:
        this->prepareTTT();
        break;
    case TYPE::THROUGHPUT_TRANSITIONS_STEADY:
        this->prepareTTsS();
        break;
    case TYPE::THROUGHPUT_TRANSITIONS_TIME:
        this->prepareTTsT();
        break;

    case TYPE::UTILIZATION_TRANSITION_STEADY:
        this->prepareUTS();
        break;
    case TYPE::UTILIZATION_TRANSITION_TIME:
        this->prepareUTT();
        break;
    case TYPE::UTILIZATION_TRANSITIONS_STEADY:
        this->prepareUTsS();
        break;
    case TYPE::UTILIZATION_TRANSITIONS_TIME:
        this->prepareUTsT();
        break;

    case TYPE::PROB_PLACE_STEADY:
        this->preparePPS();
        break;
    case TYPE::PROB_PLACE_TIME:
        this->preparePPT();
        break;
    case TYPE::PROB_PLACES_STEADY:
        this->preparePPsS();
        break;
    case TYPE::PROB_PLACES_TIME:
        this->preparePPsT();
        break;

    case TYPE::EXPECTED_REWARD_STEADY:
        this->prepareERS();
        break;
    case TYPE::EXPECTED_REWARD_TIME:
        this->prepareERT();
        break;
    case TYPE::EXPECTED_ACCUMULATED_ABSORTION:
        this->prepareEAA();
        break;
    case TYPE::EXPECTED_ACCUMULATED_TIME:
        this->prepareEAT();
        break;
    case TYPE::STEADY_DEFAULT:
        this->prepareSD();
        break;
    case TYPE::VARIABLE:
        this->prepareV();
        break;
    default:
        this->prepareNull();
        break;
    }
}

std::string spnp::OutputFunction::getClassNodeName()
{
    return "output_funcion";
}

void spnp::OutputFunction::prepareData()
{
    this->functionName = "outFunc" + std::to_string(this->functionNumber);
    this->prepareFunction();
}

void spnp::OutputFunction::prepareETPS()
{
    this->functionString = "double " + this->functionName + "() {\n";
    this->functionString+= "\treturn(mark("+ objId +"));\n}\n";

    this->descriptionString = "Expected # of tokens of the place " + objId + " in steady-state";

    this->finalString = "\tsolve(INFINITY);\n";
    this->finalString += "pr_expected(\""+ this->descriptionString +"\","+ this->functionName +")";
}

void spnp::OutputFunction::prepareETPT()
{
    this->functionString = "double " + this->functionName + "() {\n";
    this->functionString+= "\treturn(mark("+ objId +"));\n}\n";

    this->descriptionString = "Expected # of tokens of the place " + objId + ": " + this->option;

    std::vector<std::string> data = this->split(this->option);
    this->finalString = "for(loop=" + data.at(0)+";loop<"+data.at(1)+";loop+="+data.at(2)+") {\n";
    this->finalString += "\tsolve((double) loop);\n";
    this->finalString += "\tpr_expected(\"Expected # of tokens of the place "+objId+"\","+this->functionName+");";
}

void spnp::OutputFunction::prepareETPsS()
{

}

void spnp::OutputFunction::prepareETPsT()
{

}

void spnp::OutputFunction::prepareTTS()
{

}

void spnp::OutputFunction::prepareTTT()
{

}

void spnp::OutputFunction::prepareTTsS()
{

}

void spnp::OutputFunction::prepareTTsT()
{

}

void spnp::OutputFunction::prepareUTS()
{

}

void spnp::OutputFunction::prepareUTT()
{

}

void spnp::OutputFunction::prepareUTsS()
{

}

void spnp::OutputFunction::prepareUTsT()
{

}

void spnp::OutputFunction::preparePPS()
{

}

void spnp::OutputFunction::preparePPT()
{

}

void spnp::OutputFunction::preparePPsS()
{

}

void spnp::OutputFunction::preparePPsT()
{

}

void spnp::OutputFunction::prepareERS()
{

}

void spnp::OutputFunction::prepareERT()
{

}

void spnp::OutputFunction::prepareEAA()
{

}

void spnp::OutputFunction::prepareEAT()
{

}

void spnp::OutputFunction::prepareSD()
{

}

void spnp::OutputFunction::prepareV()
{

}

void spnp::OutputFunction::prepareNull()
{

}

std::vector<std::string> spnp::OutputFunction::split(std::string in)
{
    std::vector<std::string> out;
    int index = -1;
    do
    {
        index = in.find(',');
        if(index>-1)
        {
            out.push_back(in.substr(0, index));
            in = in.substr(index+1, in.size());
        }
        else
        {
            out.push_back(in);
        }
    } while(index > -1);

    return out;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: bibmod.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 19:13:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <tools/resmgr.hxx>
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef SVTOOLS_URIHELPER_HXX
#include <svtools/urihelper.hxx>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XLOCALIZEDALIASES_HPP_
#include <com/sun/star/util/XLocalizedAliases.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XLOCALIZABLE_HPP_
#include <com/sun/star/lang/XLocalizable.hpp>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "bibmod.hxx"
#include "bibresid.hxx"
#include "datman.hxx"
#include "bibconfig.hxx"
static PtrBibModul pBibModul=NULL;
static sal_uInt32 nBibModulCount=0;

#ifndef _UCBHELPER_CONTENT_HXX
#include <ucbhelper/content.hxx>
#endif

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::ucb;

#define C2U(cChar) OUString::createFromAscii(cChar)
#define C2S(cChar) String::CreateFromAscii(cChar)

HdlBibModul OpenBibModul()
{
    if(pBibModul==NULL)
    {
        pBibModul=new BibModul();
    }
    nBibModulCount++;
    return &pBibModul;
}

void CloseBibModul(HdlBibModul ppBibModul)
{
    nBibModulCount--;
    if(nBibModulCount==0 && ppBibModul!=NULL)
    {
        delete pBibModul;
        pBibModul=NULL;
    }
}

BibResId::BibResId( sal_uInt16 nId ) :
    ResId( nId, pBibModul->GetResMgr() )
{
}
BibConfig* BibModul::pBibConfig = 0;
BibModul::BibModul()
{
    pResMgr = ResMgr::CreateResMgr( "bib" MAKE_NUMSTR(SUPD) );
}

BibModul::~BibModul()
{
    delete pResMgr;
    delete pBibConfig;
    pBibConfig = 0;
}

BibDataManager*  BibModul::createDataManager()
{
    return new BibDataManager();
}
//-----------------------------------------------------------------------------
BibConfig*  BibModul::GetConfig()
{
    if(! pBibConfig)
        pBibConfig = new BibConfig;
    return pBibConfig;
}

// PropertyNames
#define STATIC_USTRING(a,b) rtl::OUString a(b)
STATIC_USTRING(FM_PROP_LABEL,C2U("Label"));
STATIC_USTRING(FM_PROP_CONTROLSOURCE,C2U("DataField"));
STATIC_USTRING(FM_PROP_NAME,C2U("Name"));
STATIC_USTRING(FM_PROP_FORMATKEY,C2U("FormatKey"));
#ifdef TF_SDBAPI
#else // !TF_SDBAPI
STATIC_USTRING(FM_PROP_EDITMODE,C2U("RecordMode"));
STATIC_USTRING(FM_PROP_CURSORSOURCETYPE,C2U("DataSelectionType"));
STATIC_USTRING(FM_PROP_CURSORSOURCE,C2U("DataSelection"));
STATIC_USTRING(FM_PROP_DATASOURCE, C2U("DataSource"));
#endif // !TF_SDBAPI
STATIC_USTRING(FM_PROP_VALUE,C2U("Value"));
STATIC_USTRING(FM_PROP_TEXT,C2U("Text"));
<commit_msg>INTEGRATION: CWS pchfix02 (1.8.186); FILE MERGED 2006/09/01 17:26:26 kaib 1.8.186.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: bibmod.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 12:55:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"

#include <tools/resmgr.hxx>
#ifndef _URLOBJ_HXX
#include <tools/urlobj.hxx>
#endif
#ifndef SVTOOLS_URIHELPER_HXX
#include <svtools/urihelper.hxx>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XLOCALIZEDALIASES_HPP_
#include <com/sun/star/util/XLocalizedAliases.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XLOCALIZABLE_HPP_
#include <com/sun/star/lang/XLocalizable.hpp>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "bibmod.hxx"
#include "bibresid.hxx"
#include "datman.hxx"
#include "bibconfig.hxx"
static PtrBibModul pBibModul=NULL;
static sal_uInt32 nBibModulCount=0;

#ifndef _UCBHELPER_CONTENT_HXX
#include <ucbhelper/content.hxx>
#endif

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::ucb;

#define C2U(cChar) OUString::createFromAscii(cChar)
#define C2S(cChar) String::CreateFromAscii(cChar)

HdlBibModul OpenBibModul()
{
    if(pBibModul==NULL)
    {
        pBibModul=new BibModul();
    }
    nBibModulCount++;
    return &pBibModul;
}

void CloseBibModul(HdlBibModul ppBibModul)
{
    nBibModulCount--;
    if(nBibModulCount==0 && ppBibModul!=NULL)
    {
        delete pBibModul;
        pBibModul=NULL;
    }
}

BibResId::BibResId( sal_uInt16 nId ) :
    ResId( nId, pBibModul->GetResMgr() )
{
}
BibConfig* BibModul::pBibConfig = 0;
BibModul::BibModul()
{
    pResMgr = ResMgr::CreateResMgr( "bib" MAKE_NUMSTR(SUPD) );
}

BibModul::~BibModul()
{
    delete pResMgr;
    delete pBibConfig;
    pBibConfig = 0;
}

BibDataManager*  BibModul::createDataManager()
{
    return new BibDataManager();
}
//-----------------------------------------------------------------------------
BibConfig*  BibModul::GetConfig()
{
    if(! pBibConfig)
        pBibConfig = new BibConfig;
    return pBibConfig;
}

// PropertyNames
#define STATIC_USTRING(a,b) rtl::OUString a(b)
STATIC_USTRING(FM_PROP_LABEL,C2U("Label"));
STATIC_USTRING(FM_PROP_CONTROLSOURCE,C2U("DataField"));
STATIC_USTRING(FM_PROP_NAME,C2U("Name"));
STATIC_USTRING(FM_PROP_FORMATKEY,C2U("FormatKey"));
#ifdef TF_SDBAPI
#else // !TF_SDBAPI
STATIC_USTRING(FM_PROP_EDITMODE,C2U("RecordMode"));
STATIC_USTRING(FM_PROP_CURSORSOURCETYPE,C2U("DataSelectionType"));
STATIC_USTRING(FM_PROP_CURSORSOURCE,C2U("DataSelection"));
STATIC_USTRING(FM_PROP_DATASOURCE, C2U("DataSource"));
#endif // !TF_SDBAPI
STATIC_USTRING(FM_PROP_VALUE,C2U("Value"));
STATIC_USTRING(FM_PROP_TEXT,C2U("Text"));
<|endoftext|>


<commit_before>// This file is part of the "kafkaping" project
//   <http://github.com/christianparpart/kafkaping>
//   (c) 2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <cstdio>
#include <cinttypes>
#include <librdkafka/rdkafkacpp.h>
#include <getopt.h>
#include <unistd.h>
#include <mutex>
#include <atomic>
#include "LogMessage.h"

void dumpConfig(RdKafka::Conf* conf, const std::string& msg) {
  std::cout << "============================== " << msg << std::endl;
  auto d = conf->dump();
  for (auto i = d->begin(), e = d->end(); i != e;) {
    std::cout << *i++ << " = " << *i++ << std::endl;
  }
  std::cout << std::endl;
}

class Kafkaping : public RdKafka::EventCb,
                 public RdKafka::DeliveryReportCb,
                 public RdKafka::ConsumeCb,
                 public RdKafka::OffsetCommitCb {
 public:
  Kafkaping(const std::string& brokers,
           const std::string& topic,
           int count,
           int interval,
           bool debug);
  ~Kafkaping();

  void producerLoop();
  void consumerLoop();

  void event_cb(RdKafka::Event& event) override;
  void dr_cb(RdKafka::Message& message) override;
  void consume_cb(RdKafka::Message& msg, void* opaque) override;
  void offset_commit_cb(RdKafka::ErrorCode err,
                        std::vector<RdKafka::TopicPartition*>& offsets) override;

  LogMessage logError() {
    return LogMessage("[ERROR] ", std::bind(&Kafkaping::logPrinter, this, std::placeholders::_1));
  }

  LogMessage logInfo() {
    return LogMessage("[INFO] ", std::bind(&Kafkaping::logPrinter, this, std::placeholders::_1));
  }

  LogMessage logDebug() {
    if (debug_) {
      return LogMessage("[DEBUG] ", std::bind(&Kafkaping::logPrinter, this, std::placeholders::_1));
    } else {
      return LogMessage("", [](auto m) {});
    }
  }

 private:
  void logPrinter(const std::string& msg) {
    std::lock_guard<decltype(stderrLock_)> _lk(stderrLock_);

    char ts[20];
    time_t t = time(nullptr);
    struct tm tm;
    localtime_r(&t, &tm);
    int timed = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", &tm);

    if (timed) {
      fprintf(stderr, "[%s] %s\n", ts, msg.c_str());
    } else {
      fprintf(stderr, "%s\n", msg.c_str());
    }
  }

  void configureGlobal(const std::string& key, const std::string& val);
  void configureTopic(const std::string& key, const std::string& val);

 private:
  RdKafka::Conf* confGlobal_;
  RdKafka::Conf* confTopic_;
  std::string topicStr_;
  std::atomic<int> count_;
  int interval_;
  bool debug_;
  int64_t startOffset_;
  std::mutex stderrLock_;
};

Kafkaping::Kafkaping(const std::string& brokers,
                   const std::string& topic,
                   int count,
                   int interval,
                   bool debug)
    : confGlobal_(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)),
      confTopic_(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)),
      topicStr_(topic),
      count_(count),
      interval_(interval),
      debug_(debug),
      startOffset_(RdKafka::Topic::OFFSET_END) {
  std::string errstr;
  confGlobal_->set("event_cb", (RdKafka::EventCb*) this, errstr);
  confGlobal_->set("dr_cb", (RdKafka::DeliveryReportCb*) this, errstr);
  confGlobal_->set("metadata.broker.list", brokers, errstr);

  configureGlobal("client.id", "kafkaping");
  configureGlobal("group.id", "kafkaping");

  configureGlobal("request.timeout.ms", "5000");
  configureGlobal("connections.max.idle.ms", "10000");
  configureGlobal("message.send.max.retries", "10");

  configureGlobal("queue.buffering.max.ms", "1"); // don't buffer inflights messages

  // XXX only interesting if we wanna use the broker's offset store
  // configureGlobal("enable.auto.commit", "true");
  // configureGlobal("auto.commit.interval.ms", "true");
  // configureGlobal("auto.offset.reset", "latest");

  if (debug_) {
    dumpConfig(confGlobal_, "global");
    dumpConfig(confTopic_, "topic");
  }
}

void Kafkaping::configureGlobal(const std::string& key, const std::string& val) {
  std::string errstr;
  confGlobal_->set(key, val, errstr);
}

void Kafkaping::configureTopic(const std::string& key, const std::string& val) {
  std::string errstr;
  confTopic_->set(key, val, errstr);
}

Kafkaping::~Kafkaping() {
}

void Kafkaping::producerLoop() {
  const int32_t partition = RdKafka::Topic::PARTITION_UA;
  std::string errstr;

  RdKafka::Producer* producer = RdKafka::Producer::create(confGlobal_, errstr);
  if (!producer) {
    logError() << "Failed to create producer " << errstr;
    exit(1);
  }
  logDebug() << "Created producer " << producer->name();

  RdKafka::Topic* topic = RdKafka::Topic::create(producer, topicStr_, confTopic_, errstr);
  if (!topic) {
    logError() << "Failed to create topic: " << errstr;
    exit(1);
  }
  logDebug() << "Created topic " << topicStr_;

  while (count_.load() != 0) {
    timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    std::string payload = std::to_string(ts.tv_sec) + "." + std::to_string(ts.tv_nsec);

    // produce
    RdKafka::ErrorCode resp = producer->produce(
        topic, partition, RdKafka::Producer::RK_MSG_COPY /* Copy payload */,
        const_cast<char*>(payload.c_str()), payload.size() + 1, nullptr, nullptr);
    if (resp != RdKafka::ERR_NO_ERROR)
      logError() << "Produce failed. " << RdKafka::err2str(resp);
    else
      logDebug() << "Produced payload:" << payload;

    // wait until flushed (no need to send another message if we can't even handle that)
    if (producer->outq_len()) {
      do producer->poll(1000);
      while (producer->outq_len() > 0);
    }
    if (interval_) {
      usleep(interval_ * 1000);
    }
  }

  while (producer->outq_len() > 0) {
    producer->poll(1000);
  }

  delete topic;
  //FIXME(doesn't return): delete producer;
}

void Kafkaping::consumerLoop() {
  const int32_t partition = 0;

  std::string errstr;
  RdKafka::Consumer *consumer = RdKafka::Consumer::create(confGlobal_, errstr);
  if (!consumer) {
    logError() << "Failed to create consumer: " << errstr;
    abort();
  }
  logDebug() << "Created consumer " << consumer->name();

  RdKafka::Topic *topic = RdKafka::Topic::create(consumer, topicStr_, confTopic_, errstr);
  if (!topic) {
    logError() << "Failed to create consumer topic: " << errstr;
    abort();
  }

  RdKafka::ErrorCode resp = consumer->start(topic, partition, startOffset_);
  if (resp != RdKafka::ERR_NO_ERROR) {
    logError() << "Failed to start consumer (" << resp << "): " << RdKafka::err2str(resp);
    abort();
  }

  while (count_.load() != 0) {
    consumer->consume_callback(topic, partition, 1000, this, nullptr);
    consumer->poll(0);
  }

  logDebug() << "Stopping consumer";
  consumer->stop(topic, partition);
  consumer->poll(1000);

  delete topic;
  delete consumer;
  logDebug() << "Stopped consumer";
}

void Kafkaping::event_cb(RdKafka::Event& event) {
  switch (event.type()) {
  case RdKafka::Event::EVENT_ERROR:
    logError() << RdKafka::err2str(event.err()) << ": " << event.str();
    // if (event.err() == RdKafka::ERR__ALL_BROKERS_DOWN)
    //   abort();
    break;
  case RdKafka::Event::EVENT_STATS:
    logDebug() << "STATS: " << event.str();
    break;
  case RdKafka::Event::EVENT_LOG:
    logDebug() << "LOG-" << event.severity() << "-" << event.fac() << ": " << event.str();
    break;
  default:
    logError() << "EVENT " << event.type() << " ("
               << RdKafka::err2str(event.err()) << "): " << event.str();
    break;
  }
}

void Kafkaping::dr_cb(RdKafka::Message& message) {
  if (message.err()) {
    logError() << "Devliery Report Failure. " << message.errstr();
  } else {
    logDebug()
        << "Delivered offset:" << message.offset()
        << " payload:" << std::string((const char*) message.payload(), message.len());
  }

  if (message.key())
    logDebug() << "Key: " << *(message.key()) << ";";
}

void Kafkaping::consume_cb(RdKafka::Message& message, void* opaque) {
  switch (message.err()) {
    case RdKafka::ERR__TIMED_OUT:
      break;
    case RdKafka::ERR_NO_ERROR: {
      if (count_.load() > 0) {
        --count_;
      }

      timespec now;
      clock_gettime(CLOCK_MONOTONIC, &now);

      long secs = 0, nsecs = 0;
      std::sscanf((char*) message.payload(), "%ld.%ld", &secs, &nsecs);
      timespec beg{secs, nsecs};

      int64_t diff = (now.tv_sec * 1000 + now.tv_nsec / 1000000) -
                     (beg.tv_sec * 1000 + beg.tv_nsec / 1000000);

      std::string broker = "<unknown>";
      confGlobal_->get("metadata.broker.list", broker);

      std::cout << "Received from " << broker << ":"
                << " topic=" << message.topic_name()
                << " partition=" << message.partition()
                << " offset=" << message.offset()
                << " time=" << diff << " ms" << std::endl;
      break;
    }
    case RdKafka::ERR__PARTITION_EOF:
      /* Last message */
      break;
    default:
      logError() << "Consume failed. " << message.errstr();
      break;
  }
}

void Kafkaping::offset_commit_cb(RdKafka::ErrorCode err,
                                std::vector<RdKafka::TopicPartition*>& offsets) {
}

void printHelp() {
  printf("Usage: kafkaping [-g] [-t topic] [-c count] [-i interval_ms] [broker list]\n");
}

int main(int argc, char* const argv[]) {
  std::string topic = "kafkaping";
  std::string brokers; // = "localhost:9092";
  int count = -1;
  int interval = 1000; // ms
  bool debug = false;

  for (bool done = false; !done;) {
    switch (getopt(argc, argv, "t:c:i:hg")) {
      case 'g':
        debug = true;
        break;
      case 't':
        topic = optarg;
        break;
      case 'c':
        count = std::atoi(optarg);
        break;
      case 'i':
        interval = std::atoi(optarg);
        break;
      case 'h':
        printHelp();
        return 0;
      case -1:
        done = true;
        break;
      default:
        printHelp();
        return 1;
    }
  }
  if (optind < argc) {
    while (optind < argc) {
      if (!brokers.empty()) {
        brokers += ",";
      }
      brokers += argv[optind++];
    }
  }

  if (brokers.empty()) {
    fprintf(stderr, "No brokers passed.\n");
    printHelp();
    return 1;
  }

  Kafkaping kafkaping(brokers, topic, count, interval, debug);

  std::thread producer(std::bind(&Kafkaping::producerLoop, &kafkaping));
  std::thread consumer(std::bind(&Kafkaping::consumerLoop, &kafkaping));

  producer.join();
  consumer.join();

  return 0;
}
<commit_msg>abstract away the console outputter so we can support other outputs soon<commit_after>// This file is part of the "kafkaping" project
//   <http://github.com/christianparpart/kafkaping>
//   (c) 2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <cstdio>
#include <cinttypes>
#include <librdkafka/rdkafkacpp.h>
#include <getopt.h>
#include <unistd.h>
#include <mutex>
#include <atomic>
#include "LogMessage.h"

void dumpConfig(RdKafka::Conf* conf, const std::string& msg) {
  std::cout << "============================== " << msg << std::endl;
  auto d = conf->dump();
  for (auto i = d->begin(), e = d->end(); i != e;) {
    std::cout << *i++ << " = " << *i++ << std::endl;
  }
  std::cout << std::endl;
}

class StatsSink {
 public:
  ~StatsSink() {}

  virtual void fill(const std::string& broker,
                    const std::string& topic,
                    int partition,
                    int64_t offset,
                    int64_t ts,
                    unsigned latencyMs) = 0;
};

class ConsoleSink : public StatsSink {
 public:
  void fill(const std::string& broker,
            const std::string& topic,
            int partition,
            int64_t offset,
            int64_t ts,
            unsigned latencyMs) override;
};

void ConsoleSink::fill(const std::string& broker,
                       const std::string& topic,
                       int partition,
                       int64_t offset,
                       int64_t ts,
                       unsigned latencyMs) {
  std::cout << "Received from " << broker << ":"
            << " topic=" << topic
            << " partition=" << partition
            << " offset=" << offset
            << " time=" << latencyMs << " ms" << std::endl;
}

class Kafkaping : public RdKafka::EventCb,
                  public RdKafka::DeliveryReportCb,
                  public RdKafka::ConsumeCb,
                  public RdKafka::OffsetCommitCb {
 public:
  Kafkaping(const std::string& brokers,
            const std::string& topic,
            int count,
            int interval,
            bool debug,
            StatsSink* sink);
  ~Kafkaping();

  void producerLoop();
  void consumerLoop();

  void event_cb(RdKafka::Event& event) override;
  void dr_cb(RdKafka::Message& message) override;
  void consume_cb(RdKafka::Message& msg, void* opaque) override;
  void offset_commit_cb(RdKafka::ErrorCode err,
                        std::vector<RdKafka::TopicPartition*>& offsets) override;

  LogMessage logError() {
    return LogMessage("[ERROR] ", std::bind(&Kafkaping::logPrinter, this, std::placeholders::_1));
  }

  LogMessage logInfo() {
    return LogMessage("[INFO] ", std::bind(&Kafkaping::logPrinter, this, std::placeholders::_1));
  }

  LogMessage logDebug() {
    if (debug_) {
      return LogMessage("[DEBUG] ", std::bind(&Kafkaping::logPrinter, this, std::placeholders::_1));
    } else {
      return LogMessage("", [](auto m) {});
    }
  }

 private:
  void logPrinter(const std::string& msg) {
    std::lock_guard<decltype(stderrLock_)> _lk(stderrLock_);

    char ts[20];
    time_t t = time(nullptr);
    struct tm tm;
    localtime_r(&t, &tm);
    int timed = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", &tm);

    if (timed) {
      fprintf(stderr, "[%s] %s\n", ts, msg.c_str());
    } else {
      fprintf(stderr, "%s\n", msg.c_str());
    }
  }

  void configureGlobal(const std::string& key, const std::string& val);
  void configureTopic(const std::string& key, const std::string& val);

 private:
  RdKafka::Conf* confGlobal_;
  RdKafka::Conf* confTopic_;
  std::string topicStr_;
  std::atomic<int> count_;
  int interval_;
  bool debug_;
  int64_t startOffset_;
  std::mutex stderrLock_;
  StatsSink* sink_;
};

Kafkaping::Kafkaping(const std::string& brokers,
                     const std::string& topic,
                     int count,
                     int interval,
                     bool debug,
                     StatsSink* sink)
    : confGlobal_(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)),
      confTopic_(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)),
      topicStr_(topic),
      count_(count),
      interval_(interval),
      debug_(debug),
      startOffset_(RdKafka::Topic::OFFSET_END),
      sink_(sink) {
  std::string errstr;
  confGlobal_->set("event_cb", (RdKafka::EventCb*) this, errstr);
  confGlobal_->set("dr_cb", (RdKafka::DeliveryReportCb*) this, errstr);
  confGlobal_->set("metadata.broker.list", brokers, errstr);

  configureGlobal("client.id", "kafkaping");
  configureGlobal("group.id", "kafkaping");

  configureGlobal("request.timeout.ms", "5000");
  configureGlobal("connections.max.idle.ms", "10000");
  configureGlobal("message.send.max.retries", "10");

  configureGlobal("queue.buffering.max.ms", "1"); // don't buffer inflights messages

  // XXX only interesting if we wanna use the broker's offset store
  // configureGlobal("enable.auto.commit", "true");
  // configureGlobal("auto.commit.interval.ms", "true");
  // configureGlobal("auto.offset.reset", "latest");

  if (debug_) {
    dumpConfig(confGlobal_, "global");
    dumpConfig(confTopic_, "topic");
  }
}

void Kafkaping::configureGlobal(const std::string& key, const std::string& val) {
  std::string errstr;
  confGlobal_->set(key, val, errstr);
}

void Kafkaping::configureTopic(const std::string& key, const std::string& val) {
  std::string errstr;
  confTopic_->set(key, val, errstr);
}

Kafkaping::~Kafkaping() {
}

void Kafkaping::producerLoop() {
  const int32_t partition = RdKafka::Topic::PARTITION_UA;
  std::string errstr;

  RdKafka::Producer* producer = RdKafka::Producer::create(confGlobal_, errstr);
  if (!producer) {
    logError() << "Failed to create producer " << errstr;
    exit(1);
  }
  logDebug() << "Created producer " << producer->name();

  RdKafka::Topic* topic = RdKafka::Topic::create(producer, topicStr_, confTopic_, errstr);
  if (!topic) {
    logError() << "Failed to create topic: " << errstr;
    exit(1);
  }
  logDebug() << "Created topic " << topicStr_;

  while (count_.load() != 0) {
    timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    std::string payload = std::to_string(ts.tv_sec) + "." + std::to_string(ts.tv_nsec);

    // produce
    RdKafka::ErrorCode resp = producer->produce(
        topic, partition, RdKafka::Producer::RK_MSG_COPY /* Copy payload */,
        const_cast<char*>(payload.c_str()), payload.size() + 1, nullptr, nullptr);
    if (resp != RdKafka::ERR_NO_ERROR)
      logError() << "Produce failed. " << RdKafka::err2str(resp);
    else
      logDebug() << "Produced payload:" << payload;

    // wait until flushed (no need to send another message if we can't even handle that)
    if (producer->outq_len()) {
      do producer->poll(1000);
      while (producer->outq_len() > 0);
    }
    if (interval_) {
      usleep(interval_ * 1000);
    }
  }

  while (producer->outq_len() > 0) {
    producer->poll(1000);
  }

  delete topic;
  //FIXME(doesn't return): delete producer;
}

void Kafkaping::consumerLoop() {
  const int32_t partition = 0;

  std::string errstr;
  RdKafka::Consumer *consumer = RdKafka::Consumer::create(confGlobal_, errstr);
  if (!consumer) {
    logError() << "Failed to create consumer: " << errstr;
    abort();
  }
  logDebug() << "Created consumer " << consumer->name();

  RdKafka::Topic *topic = RdKafka::Topic::create(consumer, topicStr_, confTopic_, errstr);
  if (!topic) {
    logError() << "Failed to create consumer topic: " << errstr;
    abort();
  }

  RdKafka::ErrorCode resp = consumer->start(topic, partition, startOffset_);
  if (resp != RdKafka::ERR_NO_ERROR) {
    logError() << "Failed to start consumer (" << resp << "): " << RdKafka::err2str(resp);
    abort();
  }

  while (count_.load() != 0) {
    consumer->consume_callback(topic, partition, 1000, this, nullptr);
    consumer->poll(0);
  }

  logDebug() << "Stopping consumer";
  consumer->stop(topic, partition);
  consumer->poll(1000);

  delete topic;
  delete consumer;
  logDebug() << "Stopped consumer";
}

void Kafkaping::event_cb(RdKafka::Event& event) {
  switch (event.type()) {
  case RdKafka::Event::EVENT_ERROR:
    logError() << RdKafka::err2str(event.err()) << ": " << event.str();
    // if (event.err() == RdKafka::ERR__ALL_BROKERS_DOWN)
    //   abort();
    break;
  case RdKafka::Event::EVENT_STATS:
    logDebug() << "STATS: " << event.str();
    break;
  case RdKafka::Event::EVENT_LOG:
    logDebug() << "LOG-" << event.severity() << "-" << event.fac() << ": " << event.str();
    break;
  default:
    logError() << "EVENT " << event.type() << " ("
               << RdKafka::err2str(event.err()) << "): " << event.str();
    break;
  }
}

void Kafkaping::dr_cb(RdKafka::Message& message) {
  if (message.err()) {
    logError() << "Devliery Report Failure. " << message.errstr();
  } else {
    logDebug()
        << "Delivered offset:" << message.offset()
        << " payload:" << std::string((const char*) message.payload(), message.len());
  }

  if (message.key())
    logDebug() << "Key: " << *(message.key()) << ";";
}

void Kafkaping::consume_cb(RdKafka::Message& message, void* opaque) {
  switch (message.err()) {
    case RdKafka::ERR__TIMED_OUT:
      break;
    case RdKafka::ERR_NO_ERROR: {
      if (count_.load() > 0) {
        --count_;
      }

      timespec now;
      clock_gettime(CLOCK_MONOTONIC, &now);

      long secs = 0, nsecs = 0;
      std::sscanf((char*) message.payload(), "%ld.%ld", &secs, &nsecs);
      timespec beg{secs, nsecs};

      int64_t diff = (now.tv_sec * 1000 + now.tv_nsec / 1000000) -
                     (beg.tv_sec * 1000 + beg.tv_nsec / 1000000);

      std::string broker = "<unknown>";
      confGlobal_->get("metadata.broker.list", broker);

      sink_->fill(broker, message.topic_name(), message.partition(),
                  message.offset(), message.timestamp().timestamp, diff);
      break;
    }
    case RdKafka::ERR__PARTITION_EOF:
      /* Last message */
      break;
    default:
      logError() << "Consume failed. " << message.errstr();
      break;
  }
}

void Kafkaping::offset_commit_cb(RdKafka::ErrorCode err,
                                std::vector<RdKafka::TopicPartition*>& offsets) {
}

void printHelp() {
  printf("Usage: kafkaping [-g] [-t topic] [-c count] [-i interval_ms] [broker list]\n");
}

int main(int argc, char* const argv[]) {
  std::string topic = "kafkaping";
  std::string brokers; // = "localhost:9092";
  int count = -1;
  int interval = 1000; // ms
  bool debug = false;

  for (bool done = false; !done;) {
    switch (getopt(argc, argv, "t:c:i:hg")) {
      case 'g':
        debug = true;
        break;
      case 't':
        topic = optarg;
        break;
      case 'c':
        count = std::atoi(optarg);
        break;
      case 'i':
        interval = std::atoi(optarg);
        break;
      case 'h':
        printHelp();
        return 0;
      case -1:
        done = true;
        break;
      default:
        printHelp();
        return 1;
    }
  }
  if (optind < argc) {
    while (optind < argc) {
      if (!brokers.empty()) {
        brokers += ",";
      }
      brokers += argv[optind++];
    }
  }

  if (brokers.empty()) {
    fprintf(stderr, "No brokers passed.\n");
    printHelp();
    return 1;
  }

  ConsoleSink consoleSink;
  Kafkaping kafkaping(brokers, topic, count, interval, debug, &consoleSink);

  std::thread producer(std::bind(&Kafkaping::producerLoop, &kafkaping));
  std::thread consumer(std::bind(&Kafkaping::consumerLoop, &kafkaping));

  producer.join();
  consumer.join();

  return 0;
}
<|endoftext|>


<commit_before>#include "scientistservice.h"

using namespace std;

//operator overloading functions for scientistSort.
bool sortByNameAsc (const Scientist &a, const Scientist &b)
{   // also makes the sort case insensitive.
    string aName = a.getName(), bName = b.getName();
    transform(aName.begin(), aName.end(), aName.begin(), ::tolower);
    transform(bName.begin(), bName.end(), bName.begin(), ::tolower);
    return aName < bName;
}
bool sortByNameDesc(const Scientist &a, const Scientist &b)
{   // also makes the sort case insensitive.
    string aName = a.getName(), bName = b.getName();
    transform(aName.begin(), aName.end(), aName.begin(), ::tolower);
    transform(bName.begin(), bName.end(), bName.begin(), ::tolower);
    return aName > bName;
}
bool sortByGender  (const Scientist &a, const Scientist &b) { return a.getGender() <  b.getGender(); }
bool sortByBirth   (const Scientist &a, const Scientist &b) { return a.getBirth()  <  b.getBirth();  }
bool sortByDeath   (const Scientist &a, const Scientist &b) { return a.getDeath()  <  b.getDeath();  }
bool sortByAge     (const Scientist &a, const Scientist &b) { return a.getAge()    <  b.getAge();    }

ScientistService::ScientistService()
{

}

vector<Scientist> ScientistService::getScientists()
{   // Uploads the list of scientists from file.

    _scientists = _data.loadScientists();

    return _scientists;
}

bool ScientistService::addScientist(string name, char gender, int birth, int death, int age)
{   // Adds a scientist to the list and updates the file.
    // Returns true if adding succeded, false otherwise.

    Scientist scientist(name, gender, birth, death, age);

    if (findScientistByName(name).size() > 0)
    {
        return false;
    }

    else
    {
        _scientists.push_back(scientist);
        _data.saveScientists(_scientists);
        return true;
    }
}
bool ScientistService::removeScientist(string name)
{   // Removes a scientist with that name from the vector. Case insensitive.
    // Returns true if removing succeded, false otherwise.

    vector<Scientist> scientistsToRemove = findScientistByName(name);

    if (scientistsToRemove.size() > 0)
    {
        for (size_t i = 0; i < scientistsToRemove.size(); i++)
        {
            Scientist toRemove = scientistsToRemove.at(i);

            _scientists.erase(remove(_scientists.begin(), _scientists.end(), toRemove), _scientists.end());
        }

        _data.saveScientists(_scientists);

        return true;
    }

    return false;
}
void ScientistService::removeAllScientists()
{   // Removes ALL scientists from the list. Be careful with this.

    _scientists.clear();

    _data.saveScientists(_scientists);
}

void ScientistService::scientistSort(int sortType)
{    // Sort by parameter: 1 = name(A-Z), 2 = name(Z-A), 3 = gender
     //							4 = birth, 5 = death, 6 = age.

    if (sortType == 1)
    {
        sort(_scientists.begin(), _scientists.end(), sortByNameAsc);
    }
    else if (sortType == 2)
    {
        sort(_scientists.begin(), _scientists.end(), sortByNameDesc);
    }
    else if (sortType == 3)
    {
        sort(_scientists.begin(), _scientists.end(), sortByGender);
    }
    else if (sortType == 4)
    {
        sort(_scientists.begin(), _scientists.end(), sortByBirth);
    }
    else if (sortType == 5)
    {
        sort(_scientists.begin(), _scientists.end(), sortByDeath);
    }
    else if (sortType == 6)
    {
        sort(_scientists.begin(), _scientists.end(), sortByAge);
    }

    _data.saveScientists(_scientists);
}
void ScientistService::scientistSortForFind(int sortType, vector<Scientist>& scientists)
{   // Sort list by sortType: 1 = name(A-Z), 2 = name(Z-A), 3 = gender,
    //                              4 = birth, 5 = death, 6 = age.
    // Sorts the list provided by the find function without saving to file,
    // so that the search result is displayed according to the search type.

    if (sortType == 1)
    {
        sort(scientists.begin(), scientists.end(), sortByNameAsc);
    }
    else if (sortType == 2)
    {
        sort(scientists.begin(), scientists.end(), sortByNameDesc);
    }
    else if (sortType == 3)
    {
        sort(scientists.begin(), scientists.end(), sortByGender);
    }
    else if (sortType == 4)
    {
        sort(scientists.begin(), scientists.end(), sortByBirth);
    }
    else if (sortType == 5)
    {
        sort(scientists.begin(), scientists.end(), sortByDeath);
    }
    else if (sortType == 6)
    {
        sort(scientists.begin(), scientists.end(), sortByAge);
    }
}

vector<Scientist> ScientistService::findScientistByName(string name)                    // Search vector by name
{   // Returns all scientists whos name includes the string entered. Case insensitive.

    vector<Scientist> scientist;
    string databaseName;
    int pos = -1;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        databaseName = _scientists[i].getName();
        transform(databaseName.begin(), databaseName.end(), databaseName.begin(), ::tolower);
        transform(name.begin(), name.end(), name.begin(), ::tolower);

        pos = databaseName.find(name);

        if (pos > -1)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(1, scientist);

    return scientist;
}
vector<Scientist> ScientistService::findScientistByGender(char gender)                  // Search vector by gender
{   // Returns all scientists of that gender.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getGender() == gender)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByBirth(int birth)                     // Search vector by year of birth
{   // Returns all scientists born that year.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getBirth() == birth)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByBirthRange(int birth1, int birth2)   // Search vector by range of birth
{   // Returns all scientists born in that year range.

    vector<Scientist> scientist;
    int temp;
    if(birth1 > birth2)
    {
        temp = birth1;
        birth1 = birth2;
        birth2 = temp;
    }
    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getBirth() >= birth1 && _scientists[i].getBirth() <= birth2)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(4, scientist);

    return scientist;
}
vector<Scientist> ScientistService::findScientistByDeath(int death)                     // Search vector by year of death
{   // Returns all scientists that died that year, or death = 0 if still alive.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getDeath() == death)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByDeathRange(int death1, int death2)   // Search vector by range of death
{   // Returns all scientists who died in that year range.

    vector<Scientist> scientist;
    int temp;
    if(death1 > death2)
    {
        temp = death1;
        death1 = death2;
        death2 = temp;
    }
    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getDeath() >= death1 && _scientists[i].getDeath() <= death2)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(5, scientist);

    return scientist;
}
vector<Scientist> ScientistService::findScientistByAge(int age)                         // Search vector by age
{   // Returns all scientists of that age.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getAge() == age)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByAgeRange(int age1, int age2)         // Search vector by range of age
{   // Returns all scientists in that age range.

    vector<Scientist> scientist;
    int temp;
    if(age1 > age2)
    {
        temp = age1;
        age1 = age2;
        age2 = temp;
    }
    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getAge() >= age1 && _scientists[i].getAge() <= age2)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(6, scientist);

    return scientist;
}
<commit_msg>add sends a single scientist instead of vector<commit_after>#include "scientistservice.h"

using namespace std;

//operator overloading functions for scientistSort.
bool sortByNameAsc (const Scientist &a, const Scientist &b)
{   // also makes the sort case insensitive.
    string aName = a.getName(), bName = b.getName();
    transform(aName.begin(), aName.end(), aName.begin(), ::tolower);
    transform(bName.begin(), bName.end(), bName.begin(), ::tolower);
    return aName < bName;
}
bool sortByNameDesc(const Scientist &a, const Scientist &b)
{   // also makes the sort case insensitive.
    string aName = a.getName(), bName = b.getName();
    transform(aName.begin(), aName.end(), aName.begin(), ::tolower);
    transform(bName.begin(), bName.end(), bName.begin(), ::tolower);
    return aName > bName;
}
bool sortByGender  (const Scientist &a, const Scientist &b) { return a.getGender() <  b.getGender(); }
bool sortByBirth   (const Scientist &a, const Scientist &b) { return a.getBirth()  <  b.getBirth();  }
bool sortByDeath   (const Scientist &a, const Scientist &b) { return a.getDeath()  <  b.getDeath();  }
bool sortByAge     (const Scientist &a, const Scientist &b) { return a.getAge()    <  b.getAge();    }

ScientistService::ScientistService()
{

}

vector<Scientist> ScientistService::getScientists()
{   // Uploads the list of scientists from file.

    _scientists = _data.loadScientists();

    return _scientists;
}

bool ScientistService::addScientist(string name, char gender, int birth, int death, int age)
{   // Adds a scientist to the list and updates the file.
    // Returns true if adding succeded, false otherwise.

    Scientist scientist(name, gender, birth, death, age);

    if (findScientistByName(name).size() > 0)
    {
        return false;
    }

    else
    {
        _scientists.push_back(scientist);
        _data.saveScientists(scientist);
        return true;
    }
}
bool ScientistService::removeScientist(string name)
{   // Removes a scientist with that name from the vector. Case insensitive.
    // Returns true if removing succeded, false otherwise.

    vector<Scientist> scientistsToRemove = findScientistByName(name);

    if (scientistsToRemove.size() > 0)
    {
        for (size_t i = 0; i < scientistsToRemove.size(); i++)
        {
            Scientist toRemove = scientistsToRemove.at(i);

            _scientists.erase(remove(_scientists.begin(), _scientists.end(), toRemove), _scientists.end());
        }

        _data.saveScientists(_scientists);

        return true;
    }

    return false;
}
void ScientistService::removeAllScientists()
{   // Removes ALL scientists from the list. Be careful with this.

    _scientists.clear();

    _data.saveScientists(_scientists);
}

void ScientistService::scientistSort(int sortType)
{    // Sort by parameter: 1 = name(A-Z), 2 = name(Z-A), 3 = gender
     //							4 = birth, 5 = death, 6 = age.

    if (sortType == 1)
    {
        sort(_scientists.begin(), _scientists.end(), sortByNameAsc);
    }
    else if (sortType == 2)
    {
        sort(_scientists.begin(), _scientists.end(), sortByNameDesc);
    }
    else if (sortType == 3)
    {
        sort(_scientists.begin(), _scientists.end(), sortByGender);
    }
    else if (sortType == 4)
    {
        sort(_scientists.begin(), _scientists.end(), sortByBirth);
    }
    else if (sortType == 5)
    {
        sort(_scientists.begin(), _scientists.end(), sortByDeath);
    }
    else if (sortType == 6)
    {
        sort(_scientists.begin(), _scientists.end(), sortByAge);
    }

    _data.saveScientists(_scientists);
}
void ScientistService::scientistSortForFind(int sortType, vector<Scientist>& scientists)
{   // Sort list by sortType: 1 = name(A-Z), 2 = name(Z-A), 3 = gender,
    //                              4 = birth, 5 = death, 6 = age.
    // Sorts the list provided by the find function without saving to file,
    // so that the search result is displayed according to the search type.

    if (sortType == 1)
    {
        sort(scientists.begin(), scientists.end(), sortByNameAsc);
    }
    else if (sortType == 2)
    {
        sort(scientists.begin(), scientists.end(), sortByNameDesc);
    }
    else if (sortType == 3)
    {
        sort(scientists.begin(), scientists.end(), sortByGender);
    }
    else if (sortType == 4)
    {
        sort(scientists.begin(), scientists.end(), sortByBirth);
    }
    else if (sortType == 5)
    {
        sort(scientists.begin(), scientists.end(), sortByDeath);
    }
    else if (sortType == 6)
    {
        sort(scientists.begin(), scientists.end(), sortByAge);
    }
}

vector<Scientist> ScientistService::findScientistByName(string name)                    // Search vector by name
{   // Returns all scientists whos name includes the string entered. Case insensitive.

    vector<Scientist> scientist;
    string databaseName;
    int pos = -1;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        databaseName = _scientists[i].getName();
        transform(databaseName.begin(), databaseName.end(), databaseName.begin(), ::tolower);
        transform(name.begin(), name.end(), name.begin(), ::tolower);

        pos = databaseName.find(name);

        if (pos > -1)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(1, scientist);

    return scientist;
}
vector<Scientist> ScientistService::findScientistByGender(char gender)                  // Search vector by gender
{   // Returns all scientists of that gender.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getGender() == gender)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByBirth(int birth)                     // Search vector by year of birth
{   // Returns all scientists born that year.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getBirth() == birth)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByBirthRange(int birth1, int birth2)   // Search vector by range of birth
{   // Returns all scientists born in that year range.

    vector<Scientist> scientist;
    int temp;
    if(birth1 > birth2)
    {
        temp = birth1;
        birth1 = birth2;
        birth2 = temp;
    }
    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getBirth() >= birth1 && _scientists[i].getBirth() <= birth2)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(4, scientist);

    return scientist;
}
vector<Scientist> ScientistService::findScientistByDeath(int death)                     // Search vector by year of death
{   // Returns all scientists that died that year, or death = 0 if still alive.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getDeath() == death)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByDeathRange(int death1, int death2)   // Search vector by range of death
{   // Returns all scientists who died in that year range.

    vector<Scientist> scientist;
    int temp;
    if(death1 > death2)
    {
        temp = death1;
        death1 = death2;
        death2 = temp;
    }
    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getDeath() >= death1 && _scientists[i].getDeath() <= death2)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(5, scientist);

    return scientist;
}
vector<Scientist> ScientistService::findScientistByAge(int age)                         // Search vector by age
{   // Returns all scientists of that age.

    vector<Scientist> scientist;

    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getAge() == age)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    return scientist;
}
vector<Scientist> ScientistService::findScientistByAgeRange(int age1, int age2)         // Search vector by range of age
{   // Returns all scientists in that age range.

    vector<Scientist> scientist;
    int temp;
    if(age1 > age2)
    {
        temp = age1;
        age1 = age2;
        age2 = temp;
    }
    for (size_t i = 0; i < _scientists.size(); i++)
    {
        if (_scientists[i].getAge() >= age1 && _scientists[i].getAge() <= age2)
        {
            scientist.push_back(_scientists[i]);
        }
    }

    scientistSortForFind(6, scientist);

    return scientist;
}
<|endoftext|>