<commit_before>/*
Copyright(c) 2016 Panos Karabelas

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

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

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

//= INCLUDES =================
#include "DirectusCore.h"
#include "Logging/Log.h"
#include <QStyleOption>
#include "Core/Settings.h"
#include "Core/Context.h"
#include "Core/Scene.h"
#include "Components/Camera.h"
#include "Math/Vector3.h"
#include "Math/Vector2.h"
#include "DirectusInspector.h"
//============================

//= NAMESPACES ================
using namespace Directus;
using namespace Directus::Math;
//=============================

// CONSTRUCTOR/DECONSTRUCTOR =========================
DirectusCore::DirectusCore(QWidget* parent) : QWidget(parent)
{
    setAttribute(Qt::WA_MSWindowsUseDirect3D, true);
    setAttribute(Qt::WA_PaintOnScreen, true);
    setAttribute(Qt::WA_NativeWindow, true);

    // This will make Qt update this widget as fast as possible.
    // Yes, paintEvent(QPaintEvent*) will be called also.
    // NOTE: I tested this technique and it yields thousands
    // of FPS, so it should do.
    m_timerUpdate = new QTimer(this);
    connect(m_timerUpdate, SIGNAL(timeout()), this, SLOT(update()));

    // stats
    m_timer500Mil = new QTimer(this);
    connect(m_timer500Mil, SIGNAL(timeout()), this, SLOT(Update500Mil()));

    // light update
    m_timer60FPS = new QTimer(this);
    connect(m_timer60FPS, SIGNAL(timeout()), this, SLOT(Update60FPS()));
    m_timer60FPS->start(16);

    m_locked = false;
    m_isRunning = false;
}

DirectusCore::~DirectusCore()
{
    m_engine->Shutdown();
    delete m_engine;
}

Socket* DirectusCore::GetEngineSocket()
{
    return m_socket;
}

void DirectusCore::Initialize(void* mainWindowHandle, void* hInstance, DirectusStatsLabel* directusStatsLabel)
{
    // Initialize the engine
    m_engine = new Engine(new Context());
    m_engine->SetHandles(hInstance, mainWindowHandle, (void*)this->winId());
    m_engine->Initialize();

    m_socket = m_engine->GetContext()->GetSubsystem<Socket>();
    m_directusStatsLabel = directusStatsLabel;
}

void DirectusCore::SetInspector(DirectusInspector* inspector)
{
    m_inspector = inspector;
}

bool DirectusCore::IsRunning()
{
    return m_isRunning;
}

// Runs when the play button is pressed
void DirectusCore::Start()
{
    if (m_locked)
        return;

    m_socket->Start();
    m_timerUpdate->start(0);
    m_timer500Mil->start(500);
    m_timer60FPS->stop();
    m_isRunning = true;

    emit EngineStarting();
}

// Runs when the play button is released
void DirectusCore::Stop()
{
    if (m_locked)
        return;

    m_socket->OnDisable();
    m_timerUpdate->stop();
    m_timer500Mil->stop();
    m_timer60FPS->start(16);
    m_isRunning = false;

    emit EngineStopping();
}

// Runs as fast as possible, performs a full simulation cycle.
void DirectusCore::Update()
{
    if (m_locked)
        return;

    m_socket->Update();
}

// Runs every second
void DirectusCore::Update500Mil()
{
    if (m_locked)
        return;

    m_directusStatsLabel->UpdateStats(this);
}

// Runs 30 times per second
// Updates engine's subsystems and propagates data, it doesn't simulate
void DirectusCore::Update60FPS()
{
    if (m_locked)
        return;

    m_socket->LightUpdate();
}

// Prevents any engine update to execute
void DirectusCore::LockUpdate()
{
    m_locked = true;
}

// Allows any engine update function to execute
void DirectusCore::UnlockUpdate()
{
    m_locked = false;
}
//====================================================

//= OVERRIDDEN FUNCTIONS =============================
void DirectusCore::resizeEvent(QResizeEvent* evt)
{
    if (evt->oldSize() == evt->size())
        return;

    int width = this->size().width();
    int height = this->size().height();

    height = width / (16.0f/9.0f);

    if (width % 2 != 0)
        width++;

    if (height % 2 != 0)
        height++;

    // Change the size of the widget
    setGeometry(QRect(0, 0, width, height));

    // Change the rendering resolution of the engine
    SetResolution(width, height);
}

// Invoked by QT itself, Update() let's the engine do the rendering
void DirectusCore::paintEvent(QPaintEvent* evt)
{
    Update();
}

// Temporary
void DirectusCore::mousePressEvent(QMouseEvent* event)
{
    /*QPoint mousePos = event->pos();
    auto picked = m_socket->GetContext()->GetSubsystem<Scene>()->MousePick(Vector2(mousePos.x(), mousePos.y()));

    if (picked)
        LOG_INFO(picked->GetName());

    m_inspector->Inspect(picked);*/
}
//===================================================

//= Engine functions ================================
// Changes the rendering resolution of the engine
void DirectusCore::SetResolution(float width, float height)
{
    if (!m_socket)
        return;

    m_socket->SetResolution(width, height);
    m_socket->SetViewport(width, height);
}
//===================================================
<commit_msg>Editor game view is no longer locked to an aspect ratio of 16:9<commit_after>/*
Copyright(c) 2016 Panos Karabelas

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

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

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

//= INCLUDES =================
#include "DirectusCore.h"
#include "Logging/Log.h"
#include <QStyleOption>
#include "Core/Settings.h"
#include "Core/Context.h"
#include "Core/Scene.h"
#include "Components/Camera.h"
#include "Math/Vector3.h"
#include "Math/Vector2.h"
#include "DirectusInspector.h"
//============================

//= NAMESPACES ================
using namespace Directus;
using namespace Directus::Math;
//=============================

// CONSTRUCTOR/DECONSTRUCTOR =========================
DirectusCore::DirectusCore(QWidget* parent) : QWidget(parent)
{
    setAttribute(Qt::WA_MSWindowsUseDirect3D, true);
    setAttribute(Qt::WA_PaintOnScreen, true);
    setAttribute(Qt::WA_NativeWindow, true);

    // This will make Qt update this widget as fast as possible.
    // Yes, paintEvent(QPaintEvent*) will be called also.
    // NOTE: I tested this technique and it yields thousands
    // of FPS, so it should do.
    m_timerUpdate = new QTimer(this);
    connect(m_timerUpdate, SIGNAL(timeout()), this, SLOT(update()));

    // stats
    m_timer500Mil = new QTimer(this);
    connect(m_timer500Mil, SIGNAL(timeout()), this, SLOT(Update500Mil()));

    // light update
    m_timer60FPS = new QTimer(this);
    connect(m_timer60FPS, SIGNAL(timeout()), this, SLOT(Update60FPS()));
    m_timer60FPS->start(16);

    m_locked = false;
    m_isRunning = false;
}

DirectusCore::~DirectusCore()
{
    m_engine->Shutdown();
    delete m_engine;
}

Socket* DirectusCore::GetEngineSocket()
{
    return m_socket;
}

void DirectusCore::Initialize(void* mainWindowHandle, void* hInstance, DirectusStatsLabel* directusStatsLabel)
{
    // Initialize the engine
    m_engine = new Engine(new Context());
    m_engine->SetHandles(hInstance, mainWindowHandle, (void*)this->winId());
    m_engine->Initialize();

    m_socket = m_engine->GetContext()->GetSubsystem<Socket>();
    m_directusStatsLabel = directusStatsLabel;
}

void DirectusCore::SetInspector(DirectusInspector* inspector)
{
    m_inspector = inspector;
}

bool DirectusCore::IsRunning()
{
    return m_isRunning;
}

// Runs when the play button is pressed
void DirectusCore::Start()
{
    if (m_locked)
        return;

    m_socket->Start();
    m_timerUpdate->start(0);
    m_timer500Mil->start(500);
    m_timer60FPS->stop();
    m_isRunning = true;

    emit EngineStarting();
}

// Runs when the play button is released
void DirectusCore::Stop()
{
    if (m_locked)
        return;

    m_socket->OnDisable();
    m_timerUpdate->stop();
    m_timer500Mil->stop();
    m_timer60FPS->start(16);
    m_isRunning = false;

    emit EngineStopping();
}

// Runs as fast as possible, performs a full simulation cycle.
void DirectusCore::Update()
{
    if (m_locked)
        return;

    m_socket->Update();
}

// Runs every second
void DirectusCore::Update500Mil()
{
    if (m_locked)
        return;

    m_directusStatsLabel->UpdateStats(this);
}

// Runs 30 times per second
// Updates engine's subsystems and propagates data, it doesn't simulate
void DirectusCore::Update60FPS()
{
    if (m_locked)
        return;

    m_socket->LightUpdate();
}

// Prevents any engine update to execute
void DirectusCore::LockUpdate()
{
    m_locked = true;
}

// Allows any engine update function to execute
void DirectusCore::UnlockUpdate()
{
    m_locked = false;
}
//====================================================

//= OVERRIDDEN FUNCTIONS =============================
void DirectusCore::resizeEvent(QResizeEvent* evt)
{
    if (evt->oldSize() == evt->size())
        return;

    int width = this->size().width();
    int height = this->size().height();

    if (width % 2 != 0)
        width++;

    if (height % 2 != 0)
        height++;

    // Change the size of the widget
    setGeometry(QRect(0, 0, width, height));

    // Change the resolution of the engine
    SetResolution(width, height);
}

// Invoked by QT itself, Update() let's the engine do the rendering
void DirectusCore::paintEvent(QPaintEvent* evt)
{
    Update();
}

// Temporary
void DirectusCore::mousePressEvent(QMouseEvent* event)
{
    /*QPoint mousePos = event->pos();
    auto picked = m_socket->GetContext()->GetSubsystem<Scene>()->MousePick(Vector2(mousePos.x(), mousePos.y()));

    if (picked)
        LOG_INFO(picked->GetName());

    m_inspector->Inspect(picked);*/
}
//===================================================

//= Engine functions ================================
// Changes the rendering resolution of the engine
void DirectusCore::SetResolution(float width, float height)
{
    if (!m_socket)
        return;

    m_socket->SetResolution(width, height);
    m_socket->SetViewport(width, height);
}
//===================================================
<|endoftext|>


<commit_before>    //  Natron
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "HistogramCPU.h"

#include <algorithm>
#include <QMutex>
#include <QWaitCondition>

#include "Engine/Image.h"

struct HistogramRequest {
    int binsCount;
    int mode;
    boost::shared_ptr<Natron::Image> image;
    RectI rect;
    double vmin;
    double vmax;
    int smoothingKernelSize;

    HistogramRequest()
    : binsCount(0)
    , mode(0)
    , image()
    , rect()
    , vmin(0)
    , vmax(0)
    , smoothingKernelSize(0)
    {

    }

    HistogramRequest(int binsCount,
                     int mode,
                     const boost::shared_ptr<Natron::Image>& image,
                     const RectI& rect,
                     double vmin,
                     double vmax,
                     int smoothingKernelSize)
    : binsCount(binsCount)
    , mode(mode)
    , image(image)
    , rect(rect)
    , vmin(vmin)
    , vmax(vmax)
    , smoothingKernelSize(smoothingKernelSize)
    {
    }
};

struct FinishedHistogram {
    std::vector<float> histogram1;
    std::vector<float> histogram2;
    std::vector<float> histogram3;
    int mode;
    int binsCount;
    int pixelsCount;
    double vmin,vmax;

    FinishedHistogram()
    : histogram1()
    , histogram2()
    , histogram3()
    , mode(0)
    , binsCount(0)
    , pixelsCount(0)
    , vmin(0)
    , vmax(0)
    {

    }
};

struct HistogramCPUPrivate
{

    QWaitCondition requestCond;
    QMutex requestMutex;
    std::list<HistogramRequest> requests;

    QMutex producedMutex;
    std::list<boost::shared_ptr<FinishedHistogram> > produced;

    QWaitCondition mustQuitCond;
    QMutex mustQuitMutex;
    bool mustQuit;

    HistogramCPUPrivate()
    : requestCond()
    , requestMutex()
    , requests()
    , producedMutex()
    , produced()
    , mustQuitCond()
    , mustQuitMutex()
    , mustQuit(false)
    {

    }
};

HistogramCPU::HistogramCPU()
: QThread()
, _imp(new HistogramCPUPrivate())
{
}

HistogramCPU::~HistogramCPU()
{
    quitAnyComputation();
}

void HistogramCPU::computeHistogram(int mode, //< corresponds to the enum Histogram::DisplayMode
                                    const boost::shared_ptr<Natron::Image>& image,
                                    const RectI& rect,
                                    int binsCount,
                                    double vmin,
                                    double vmax,
                                    int smoothingKernelSize)
{
    /*Starting or waking-up the thread*/
    QMutexLocker quitLocker(&_imp->mustQuitMutex);
    QMutexLocker locker(&_imp->requestMutex);
    _imp->requests.push_back(HistogramRequest(binsCount,mode,image,rect,vmin,vmax,smoothingKernelSize));
    if (!isRunning() && !_imp->mustQuit) {
        quitLocker.unlock();
        start(HighestPriority);
    } else {
        quitLocker.unlock();
        _imp->requestCond.wakeOne();
    }

}

void HistogramCPU::quitAnyComputation()
{
    if (isRunning()) {
        QMutexLocker l(&_imp->mustQuitMutex);
        _imp->mustQuit = true;

        ///post a fake request to wakeup the thread
        l.unlock();
        computeHistogram(0, boost::shared_ptr<Natron::Image>(), RectI(), 0,0,0,0);
        l.relock();
        while (_imp->mustQuit) {
            _imp->mustQuitCond.wait(&_imp->mustQuitMutex);
        }
    }
}

bool
HistogramCPU::hasProducedHistogram() const
{
    QMutexLocker l(&_imp->producedMutex);
    return !_imp->produced.empty();
}

bool
HistogramCPU::getMostRecentlyProducedHistogram(std::vector<float>* histogram1,
                                               std::vector<float>* histogram2,
                                               std::vector<float>* histogram3,
                                               unsigned int* binsCount,
                                               unsigned int* pixelsCount,
                                               int* mode,
                                               double* vmin,
                                               double* vmax)
{
    assert(histogram1 && histogram2 && histogram3 && binsCount && pixelsCount && mode && vmin && vmax);

    QMutexLocker l(&_imp->producedMutex);
    if (_imp->produced.empty()) {
        return false;
    }

#pragma message WARN("this is not the most recent! the most recent is back(), since we push_back() below")
    boost::shared_ptr<FinishedHistogram> h = _imp->produced.front();

    *histogram1 = h->histogram1;
    *histogram2 = h->histogram2;
    *histogram3 = h->histogram3;
    *binsCount = h->binsCount;
    *pixelsCount = h->pixelsCount;
    *mode = h->mode;
    *vmin = h->vmin;
    *vmax = h->vmax;
    _imp->produced.pop_front();

    return true;
}

static inline float
pix_red(float *pix)
{
    return pix[0];
}

static inline float
pix_green(float *pix)
{
    return pix[1];
}

static inline float
pix_blue(float *pix)
{
    return pix[2];
}

static inline float
pix_alpha(float *pix)
{
    return pix[3];
}

static inline float
pix_lum(float *pix)
{
    return 0.299 * pix[0] + 0.587 * pix[1] + 0.114 * pix[2];
}

template <float pix_func(float*)>
void
computeHisto(const HistogramRequest& request, std::vector<float> *histo)
{
    assert(histo);
    histo->resize(request.binsCount);
    std::fill(histo->begin(), histo->end(), 0.f);

    double binSize = (request.vmax - request.vmin) / request.binsCount;

    for (int y = request.rect.bottom() ; y < request.rect.top(); ++y) {
        for (int x = request.rect.left(); x < request.rect.right(); ++x) {
            float *pix = request.image->pixelAt(x, y) ;
            float v = pix_func(pix);
            if (request.vmin <= v && v < request.vmax) {
                int index = (int)((v - request.vmin) / binSize);
                assert(0 <= index && index < (int)histo->size());
                (*histo)[index] += 1.f;
            }
        }
    }
}

static void
computeHistogramStatic(const HistogramRequest& request, boost::shared_ptr<FinishedHistogram> ret, int histogramIndex)
{
    std::vector<float> *histo = 0;
    switch (histogramIndex) {
        case 1:
            histo = &ret->histogram1;
            break;
        case 2:
            histo = &ret->histogram2;
            break;
        case 3:
            histo = &ret->histogram3;
            break;
        default:
            break;
    }
    assert(histo);

    /// keep the mode parameter in sync with Histogram::DisplayMode

    int mode = request.mode;

    ///if the mode is RGB, adjust the mode to either R,G or B depending on the histogram index
    if (mode == 0) {
        mode = histogramIndex + 2;
    }

    ret->pixelsCount = request.rect.area();

    switch (mode) {
        case 1: //< A
            computeHisto<pix_alpha>(request, histo);
            break;
        case 2: //<Y
            computeHisto<pix_lum>(request, histo);
            break;
        case 3: //< R
            computeHisto<pix_red>(request, histo);
            break;
        case 4: //< G
            computeHisto<pix_green>(request, histo);
            break;
        case 5: //< B
            computeHisto<pix_blue>(request, histo);
            break;

        default:
            assert(false);
            break;
    }

    ///Apply the binomial filter if any (the filter size has to be an odd number)
    assert(request.smoothingKernelSize >= 0);
    assert((request.smoothingKernelSize == 0) || (request.smoothingKernelSize & 1));

    for (int k = request.smoothingKernelSize; k > 1; k -=2) {
        const std::vector<float> histogramCopy = *histo;

        for (int i = 1; i < ((int)histo->size() - 1); ++i) {
            (*histo)[i] = (histogramCopy[i-1] + 2*histogramCopy[i] + histogramCopy[i+1]) / 4;
        }
    }
}

void
HistogramCPU::run()
{
    for (;;) {
        HistogramRequest request;
        {
            QMutexLocker l(&_imp->requestMutex);
            while (_imp->requests.empty()) {
                _imp->requestCond.wait(&_imp->requestMutex);
            }

            ///get the last request
            request = _imp->requests.back();
            _imp->requests.pop_back();

            ///ignore all other requests pending
            _imp->requests.clear();
        }

        {
            QMutexLocker l(&_imp->mustQuitMutex);
            if (_imp->mustQuit) {
                _imp->mustQuit = false;
                _imp->mustQuitCond.wakeOne();
                return;
            }
        }

        boost::shared_ptr<FinishedHistogram> ret(new FinishedHistogram);
        ret->binsCount = request.binsCount;
        ret->mode = request.mode;
        ret->vmin = request.vmin;
        ret->vmax = request.vmax;

        switch (request.mode) {
            case 0: //< RGB
                computeHistogramStatic(request, ret, 1);
                computeHistogramStatic(request, ret, 2);
                computeHistogramStatic(request, ret, 3);
                break;
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
                computeHistogramStatic(request, ret, 1);
                break;
            default:
                assert(false); //< unknown case.
                break;
        }

        {
            QMutexLocker l(&_imp->producedMutex);
            _imp->produced.push_back(ret);
        }
        emit histogramProduced();
    }
}<commit_msg>HistogramCPU: try to fix the build<commit_after>    //  Natron
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "HistogramCPU.h"

#include <algorithm>
#include <QMutex>
#include <QWaitCondition>

#include "Engine/Image.h"

struct HistogramRequest {
    int binsCount;
    int mode;
    boost::shared_ptr<Natron::Image> image;
    RectI rect;
    double vmin;
    double vmax;
    int smoothingKernelSize;

    HistogramRequest()
    : binsCount(0)
    , mode(0)
    , image()
    , rect()
    , vmin(0)
    , vmax(0)
    , smoothingKernelSize(0)
    {

    }

    HistogramRequest(int binsCount,
                     int mode,
                     const boost::shared_ptr<Natron::Image>& image,
                     const RectI& rect,
                     double vmin,
                     double vmax,
                     int smoothingKernelSize)
    : binsCount(binsCount)
    , mode(mode)
    , image(image)
    , rect(rect)
    , vmin(vmin)
    , vmax(vmax)
    , smoothingKernelSize(smoothingKernelSize)
    {
    }
};

struct FinishedHistogram {
    std::vector<float> histogram1;
    std::vector<float> histogram2;
    std::vector<float> histogram3;
    int mode;
    int binsCount;
    int pixelsCount;
    double vmin,vmax;

    FinishedHistogram()
    : histogram1()
    , histogram2()
    , histogram3()
    , mode(0)
    , binsCount(0)
    , pixelsCount(0)
    , vmin(0)
    , vmax(0)
    {

    }
};

struct HistogramCPUPrivate
{

    QWaitCondition requestCond;
    QMutex requestMutex;
    std::list<HistogramRequest> requests;

    QMutex producedMutex;
    std::list<boost::shared_ptr<FinishedHistogram> > produced;

    QWaitCondition mustQuitCond;
    QMutex mustQuitMutex;
    bool mustQuit;

    HistogramCPUPrivate()
    : requestCond()
    , requestMutex()
    , requests()
    , producedMutex()
    , produced()
    , mustQuitCond()
    , mustQuitMutex()
    , mustQuit(false)
    {

    }
};

HistogramCPU::HistogramCPU()
: QThread()
, _imp(new HistogramCPUPrivate())
{
}

HistogramCPU::~HistogramCPU()
{
    quitAnyComputation();
}

void HistogramCPU::computeHistogram(int mode, //< corresponds to the enum Histogram::DisplayMode
                                    const boost::shared_ptr<Natron::Image>& image,
                                    const RectI& rect,
                                    int binsCount,
                                    double vmin,
                                    double vmax,
                                    int smoothingKernelSize)
{
    /*Starting or waking-up the thread*/
    QMutexLocker quitLocker(&_imp->mustQuitMutex);
    QMutexLocker locker(&_imp->requestMutex);
    _imp->requests.push_back(HistogramRequest(binsCount,mode,image,rect,vmin,vmax,smoothingKernelSize));
    if (!isRunning() && !_imp->mustQuit) {
        quitLocker.unlock();
        start(HighestPriority);
    } else {
        quitLocker.unlock();
        _imp->requestCond.wakeOne();
    }

}

void HistogramCPU::quitAnyComputation()
{
    if (isRunning()) {
        QMutexLocker l(&_imp->mustQuitMutex);
        _imp->mustQuit = true;

        ///post a fake request to wakeup the thread
        l.unlock();
        computeHistogram(0, boost::shared_ptr<Natron::Image>(), RectI(), 0,0,0,0);
        l.relock();
        while (_imp->mustQuit) {
            _imp->mustQuitCond.wait(&_imp->mustQuitMutex);
        }
    }
}

bool
HistogramCPU::hasProducedHistogram() const
{
    QMutexLocker l(&_imp->producedMutex);
    return !_imp->produced.empty();
}

bool
HistogramCPU::getMostRecentlyProducedHistogram(std::vector<float>* histogram1,
                                               std::vector<float>* histogram2,
                                               std::vector<float>* histogram3,
                                               unsigned int* binsCount,
                                               unsigned int* pixelsCount,
                                               int* mode,
                                               double* vmin,
                                               double* vmax)
{
    assert(histogram1 && histogram2 && histogram3 && binsCount && pixelsCount && mode && vmin && vmax);

    QMutexLocker l(&_imp->producedMutex);
    if (_imp->produced.empty()) {
        return false;
    }

#pragma message WARN("this is not the most recent! the most recent is back(), since we push_back() below")
    boost::shared_ptr<FinishedHistogram> h = _imp->produced.front();

    *histogram1 = h->histogram1;
    *histogram2 = h->histogram2;
    *histogram3 = h->histogram3;
    *binsCount = h->binsCount;
    *pixelsCount = h->pixelsCount;
    *mode = h->mode;
    *vmin = h->vmin;
    *vmax = h->vmax;
    _imp->produced.pop_front();

    return true;
}

namespace {
struct pix_red {
    static float
    val(float *pix)
    {
        return pix[0];
    }
};

struct pix_green {
    static float
    val(float *pix)
    {
        return pix[1];
    }
};

struct pix_blue {
    static float
    val(float *pix)
    {
        return pix[2];
    }
};

struct pix_alpha {
    static float
    val(float *pix)
    {
        return pix[3];
    }
};

struct pix_lum {
    static float
    val(float *pix)
    {
        return 0.299 * pix[0] + 0.587 * pix[1] + 0.114 * pix[2];
    }
};
}

template <float pix_func(float*)>
void
computeHisto(const HistogramRequest& request, std::vector<float> *histo)
{
    assert(histo);
    histo->resize(request.binsCount);
    std::fill(histo->begin(), histo->end(), 0.f);

    double binSize = (request.vmax - request.vmin) / request.binsCount;

    for (int y = request.rect.bottom() ; y < request.rect.top(); ++y) {
        for (int x = request.rect.left(); x < request.rect.right(); ++x) {
            float *pix = request.image->pixelAt(x, y) ;
            float v = pix_func(pix);
            if (request.vmin <= v && v < request.vmax) {
                int index = (int)((v - request.vmin) / binSize);
                assert(0 <= index && index < (int)histo->size());
                (*histo)[index] += 1.f;
            }
        }
    }
}

static void
computeHistogramStatic(const HistogramRequest& request, boost::shared_ptr<FinishedHistogram> ret, int histogramIndex)
{
    std::vector<float> *histo = 0;
    switch (histogramIndex) {
        case 1:
            histo = &ret->histogram1;
            break;
        case 2:
            histo = &ret->histogram2;
            break;
        case 3:
            histo = &ret->histogram3;
            break;
        default:
            break;
    }
    assert(histo);

    /// keep the mode parameter in sync with Histogram::DisplayMode

    int mode = request.mode;

    ///if the mode is RGB, adjust the mode to either R,G or B depending on the histogram index
    if (mode == 0) {
        mode = histogramIndex + 2;
    }

    ret->pixelsCount = request.rect.area();

    switch (mode) {
        case 1: //< A
            computeHisto<&pix_alpha::val>(request, histo);
            break;
        case 2: //<Y
            computeHisto<&pix_lum::val>(request, histo);
            break;
        case 3: //< R
            computeHisto<&pix_red::val>(request, histo);
            break;
        case 4: //< G
            computeHisto<&pix_green::val>(request, histo);
            break;
        case 5: //< B
            computeHisto<&pix_blue::val>(request, histo);
            break;

        default:
            assert(false);
            break;
    }

    ///Apply the binomial filter if any (the filter size has to be an odd number)
    assert(request.smoothingKernelSize >= 0);
    assert((request.smoothingKernelSize == 0) || (request.smoothingKernelSize & 1));

    for (int k = request.smoothingKernelSize; k > 1; k -=2) {
        const std::vector<float> histogramCopy = *histo;

        for (int i = 1; i < ((int)histo->size() - 1); ++i) {
            (*histo)[i] = (histogramCopy[i-1] + 2*histogramCopy[i] + histogramCopy[i+1]) / 4;
        }
    }
}

void
HistogramCPU::run()
{
    for (;;) {
        HistogramRequest request;
        {
            QMutexLocker l(&_imp->requestMutex);
            while (_imp->requests.empty()) {
                _imp->requestCond.wait(&_imp->requestMutex);
            }

            ///get the last request
            request = _imp->requests.back();
            _imp->requests.pop_back();

            ///ignore all other requests pending
            _imp->requests.clear();
        }

        {
            QMutexLocker l(&_imp->mustQuitMutex);
            if (_imp->mustQuit) {
                _imp->mustQuit = false;
                _imp->mustQuitCond.wakeOne();
                return;
            }
        }

        boost::shared_ptr<FinishedHistogram> ret(new FinishedHistogram);
        ret->binsCount = request.binsCount;
        ret->mode = request.mode;
        ret->vmin = request.vmin;
        ret->vmax = request.vmax;

        switch (request.mode) {
            case 0: //< RGB
                computeHistogramStatic(request, ret, 1);
                computeHistogramStatic(request, ret, 2);
                computeHistogramStatic(request, ret, 3);
                break;
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
                computeHistogramStatic(request, ret, 1);
                break;
            default:
                assert(false); //< unknown case.
                break;
        }

        {
            QMutexLocker l(&_imp->producedMutex);
            _imp->produced.push_back(ret);
        }
        emit histogramProduced();
    }
}<|endoftext|>


<commit_before>/*$Id$
 *
 * This source file is a part of the Berlin Project.
 * Copyright (C) 2000 Stefan Seefeld <stefan@berlin-consortium.org>
 * Copyright (C) 2001 Philip Philonenko <philonenko@orgacom.ru>
 * http://www.berlin-consortium.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#include <Prague/Sys/Memory.hh>
#include <Prague/Sys/FdSet.hh>
#include <Prague/Sys/Tracer.hh>
#include <Prague/Sys/Path.hh>
#include <Berlin/RCManager.hh>
#include <Berlin/Logger.hh>

#include <Console/SDL/Console.hh>
#include <Console/SDL/Extension.hh>
#include <Console/SDL/Drawable.hh>
#include <Console/SDL/Pointer.hh>

using namespace Warsaw;

namespace
{
  static void readEvent(SDL_Event &e)
  {
    Prague::Trace trace("readEvent()");
    unsigned int t;
    std::cin >> t;
    e.type = static_cast<char>(t);
    switch (e.type)
      {
      case SDL_KEYDOWN:
	{
	  std::cin >> t;
	  e.key.keysym.sym = static_cast<SDLKey>(t);
	  break;
	}
      case SDL_MOUSEMOTION:
	{
	  std::cin >> e.motion.x
		   >> e.motion.y;
	  break;
	}
      case SDL_MOUSEBUTTONDOWN:
      case SDL_MOUSEBUTTONUP:
	{
	  break;
      }
      }
  }

  static void writeEvent(SDL_Event &e)
  {
    Prague::Trace trace("writeEvent()");
    std::cout << static_cast<unsigned int>(e.type) << ' ';
    switch (e.type)
      {
      case SDL_KEYDOWN:
	{
	  std::cout << static_cast<unsigned int>(e.key.keysym.sym);
	  break;
	}
      case SDL_MOUSEMOTION:
	{
	  std::cout << e.motion.x << ' '
		    << e.motion.y;
	  break;
	}
      case SDL_MOUSEBUTTONDOWN:
      case SDL_MOUSEBUTTONUP:
	{
	  break;
	}
      }
    std::cout << endl;
  }
}; // namespace

// ---------------------------------------------------------------
// class SDL::Console (implementation)
// ---------------------------------------------------------------

SDL::Console::Console(int &argc, char **argv) :
  _autoplay(false),
  _is_gl(false),
  _pointer_mgr(new PointerManagerT<nonGLPointer>)
{
  Prague::Trace trace("SDL::Console::Console");
  Logger::log(Logger::loader) << "trying to open SDL console" << endl;

  SDL_Init(SDL_INIT_VIDEO);
  SDL_ShowCursor(SDL_DISABLE);

  // FIXME: Get some 'real' values!
  _resolution[0] = 0.1;
  _resolution[1] = 0.1;

  _size[0] = 640;
  _size[1] = 480;

  _vsize[0] = 640;
  _vsize[1] = 480;

  pipe(_wakeupPipe);
}

SDL::Console::~Console()
{
  Prague::Trace trace("SDL::Console::~Console");

  for (dlist_t::iterator i = _drawables.begin();
       i != _drawables.end();
       i++) delete *i;
  close(_wakeupPipe[0]);
  close(_wakeupPipe[1]);
  SDL_Quit();
}

Console::Pointer *SDL::Console::pointer(Raster_ptr raster)
{
  Prague::Trace trace("SDL::Console::pointer");
  return _pointer_mgr->create_pointer(raster);
}

Console::Drawable *SDL::Console::drawable()
{
  Prague::Trace trace("SDL::Console::drawable");

  if (_drawables.empty())
    _drawables.push_back(new SDL::Drawable(0));

  return _drawables.front();
}

Console::Drawable *
SDL::Console::create_drawable(Warsaw::PixelCoord w,
			      Warsaw::PixelCoord h, Warsaw::PixelCoord d)
{
  Prague::Trace trace("SDL::Console::create_drawable");

  _drawables.push_back(new SDL::Drawable("display-memory", w, h, d));
  return _drawables.back();
}

Console::Drawable *SDL::Console::reference_to_servant(Warsaw::Drawable_ptr drawable)
{
  Prague::Trace trace("SDL::Console::reference_to_servant()");

  PortableServer::Servant servant = Console::reference_to_servant(drawable);
  for (dlist_t::iterator i = _drawables.begin(); i != _drawables.end(); ++i)
    if (*i == servant) return *i;
  return 0;
}

void SDL::Console::activate_autoplay()
{
  Prague::Trace trace("SDL::Console::activate_autoplay()");

  // FIXME: This should do something.
}

void SDL::Console::device_info(std::ostream &os)
{
  Prague::Trace trace("SDL::Console::device_info()");

  os << "sorry, device info isn't available for SDL at this time" << std::endl;
}

Input::Event *SDL::Console::next_event()
{
  Prague::Trace trace("SDL::Console::next_event()");

  SDL_Event event;
  SDL_WaitEvent(&event);
  return synthesize(event);
}

void SDL::Console::wakeup()
{
  Prague::Trace trace("SDL::Console::wakeup()");

  char c = 'z'; write(_wakeupPipe[1],&c,1);
}

Input::Event *SDL::Console::synthesize(const SDL_Event &e)
{
  Prague::Trace trace("SDL::Console::synthesize()");

  Input::Event_var event = new Input::Event;
  switch (e.type)
    {
    case SDL_KEYDOWN:
      {
	Input::Toggle toggle;
	toggle.actuation = Input::Toggle::press;
	toggle.number = e.key.keysym.sym;
	event->length(1);
	event[0].dev = 0;
	event[0].attr.selection(toggle); event[0].attr._d(Input::key);
	break;
      }
    case SDL_MOUSEMOTION:
      {
	// grab waiting mouse events and skip to the last one
	SDL_Event move_events[64];
	SDL_PumpEvents();
	int num = SDL_PeepEvents(move_events, 64, SDL_GETEVENT, SDL_MOUSEMOTIONMASK);
	if (num > 0)
	  {
	    // Use last known position of mouse
	    _position[0] = move_events[num-1].motion.x;
	    _position[1] = move_events[num-1].motion.y;
	  }
	else
	  {
	    // Use position from original event
	    _position[0] = e.motion.x;
	    _position[1] = e.motion.y;
	  }
	Input::Position position;
	position.x = _position[0]/_resolution[0];
	position.y = _position[1]/_resolution[1];
	position.z = 0;
	event->length(1);
	event[0].dev = 1;
	event[0].attr.location(position);
	break;
      }
    case SDL_MOUSEBUTTONDOWN:
    case SDL_MOUSEBUTTONUP:
      {
	Input::Toggle toggle;
	if (e.type == SDL_MOUSEBUTTONDOWN)
	  toggle.actuation = Input::Toggle::press;
	else
	  toggle.actuation = Input::Toggle::release;
	toggle.number = e.button.button;
	Input::Position position;
	position.x = _position[0]/_resolution[0];
	position.y = _position[1]/_resolution[1];
	position.z = 0;
	event->length(2);
	event[0].dev = 1;
	event[0].attr.selection(toggle); event[0].attr._d(Input::button);
	event[1].dev = 1;
	event[1].attr.location(position);
	break;
      }
    case SDL_QUIT:
      {
	// this is a CTRL+C sent to the controlling terminal. Berlin may be
	// already crashed, so terminate forcibly.
	exit(0);
	break;
      }
    }

  return event._retn();
}

void SDL::Console::set_PointerManager(PointerManager * pm) {
  _pointer_mgr = pm;
}

Console::Extension * SDL::Console::create_extension(const std::string & id)
{
  Prague::Trace trace("SDL::Console::create_extension()");

  if (id == "Renderer")
    return new SDL::Renderer();
  if (id == "GLContext") {
    Prague::Path path = RCManager::get_path("modulepath");
    std::string name = path.lookup_file("Console/SDLGL.so");
    Prague::Plugin<Extension> * plugin = 0;
    if (name.empty())
      {
	std::string msg =
	  "GLContext extension for SDL console not found in modulepath.";
	throw std::runtime_error(msg);
      }
    else {
      plugin = new Prague::Plugin<Extension>(name);
      _modules.push_back(plugin);
      _is_gl = 1;
      return plugin->get();
    }
  }
  if (id == "DirectBuffer")
    return new SDL::DirectBuffer();
  return 0;
}

// ---------------------------------------------------------------
// externs
// ---------------------------------------------------------------

extern "C" ::Console::LoaderT<SDL::Console> *load() { return new Console::LoaderT<SDL::Console>(); }
<commit_msg>Minor change, prevents SDLConsole from doing screwy things like treating 'shift' as a foreign-language character.<commit_after>/*$Id$
 *
 * This source file is a part of the Berlin Project.
 * Copyright (C) 2000 Stefan Seefeld <stefan@berlin-consortium.org>
 * Copyright (C) 2001 Philip Philonenko <philonenko@orgacom.ru>
 * http://www.berlin-consortium.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */

#include <Prague/Sys/Memory.hh>
#include <Prague/Sys/FdSet.hh>
#include <Prague/Sys/Tracer.hh>
#include <Prague/Sys/Path.hh>
#include <Berlin/RCManager.hh>
#include <Berlin/Logger.hh>

#include <Console/SDL/Console.hh>
#include <Console/SDL/Extension.hh>
#include <Console/SDL/Drawable.hh>
#include <Console/SDL/Pointer.hh>

using namespace Warsaw;

namespace
{
  static void readEvent(SDL_Event &e)
  {
    Prague::Trace trace("readEvent()");
    unsigned int t;
    std::cin >> t;
    e.type = static_cast<char>(t);
    switch (e.type)
      {
      case SDL_KEYDOWN:
	{
	  std::cin >> t;
	  e.key.keysym.sym = static_cast<SDLKey>(t);
	  break;
	}
      case SDL_MOUSEMOTION:
	{
	  std::cin >> e.motion.x
		   >> e.motion.y;
	  break;
	}
      case SDL_MOUSEBUTTONDOWN:
      case SDL_MOUSEBUTTONUP:
	{
	  break;
      }
      }
  }

  static void writeEvent(SDL_Event &e)
  {
    Prague::Trace trace("writeEvent()");
    std::cout << static_cast<unsigned int>(e.type) << ' ';
    switch (e.type)
      {
      case SDL_KEYDOWN:
	{
	  std::cout << static_cast<unsigned int>(e.key.keysym.sym);
	  break;
	}
      case SDL_MOUSEMOTION:
	{
	  std::cout << e.motion.x << ' '
		    << e.motion.y;
	  break;
	}
      case SDL_MOUSEBUTTONDOWN:
      case SDL_MOUSEBUTTONUP:
	{
	  break;
	}
      }
    std::cout << endl;
  }
}; // namespace

// ---------------------------------------------------------------
// class SDL::Console (implementation)
// ---------------------------------------------------------------

SDL::Console::Console(int &argc, char **argv) :
  _autoplay(false),
  _is_gl(false),
  _pointer_mgr(new PointerManagerT<nonGLPointer>)
{
  Prague::Trace trace("SDL::Console::Console");
  Logger::log(Logger::loader) << "trying to open SDL console" << endl;

  SDL_Init(SDL_INIT_VIDEO);
  SDL_ShowCursor(SDL_DISABLE);
  SDL_EnableUNICODE(SDL_ENABLE);

  // FIXME: Get some 'real' values!
  _resolution[0] = 0.1;
  _resolution[1] = 0.1;

  _size[0] = 640;
  _size[1] = 480;

  _vsize[0] = 640;
  _vsize[1] = 480;

  pipe(_wakeupPipe);
}

SDL::Console::~Console()
{
  Prague::Trace trace("SDL::Console::~Console");

  for (dlist_t::iterator i = _drawables.begin();
       i != _drawables.end();
       i++) delete *i;
  close(_wakeupPipe[0]);
  close(_wakeupPipe[1]);
  SDL_Quit();
}

Console::Pointer *SDL::Console::pointer(Raster_ptr raster)
{
  Prague::Trace trace("SDL::Console::pointer");
  return _pointer_mgr->create_pointer(raster);
}

Console::Drawable *SDL::Console::drawable()
{
  Prague::Trace trace("SDL::Console::drawable");

  if (_drawables.empty())
    _drawables.push_back(new SDL::Drawable(0));

  return _drawables.front();
}

Console::Drawable *
SDL::Console::create_drawable(Warsaw::PixelCoord w,
			      Warsaw::PixelCoord h, Warsaw::PixelCoord d)
{
  Prague::Trace trace("SDL::Console::create_drawable");

  _drawables.push_back(new SDL::Drawable("display-memory", w, h, d));
  return _drawables.back();
}

Console::Drawable *SDL::Console::reference_to_servant(Warsaw::Drawable_ptr drawable)
{
  Prague::Trace trace("SDL::Console::reference_to_servant()");

  PortableServer::Servant servant = Console::reference_to_servant(drawable);
  for (dlist_t::iterator i = _drawables.begin(); i != _drawables.end(); ++i)
    if (*i == servant) return *i;
  return 0;
}

void SDL::Console::activate_autoplay()
{
  Prague::Trace trace("SDL::Console::activate_autoplay()");

  // FIXME: This should do something.
}

void SDL::Console::device_info(std::ostream &os)
{
  Prague::Trace trace("SDL::Console::device_info()");

  os << "sorry, device info isn't available for SDL at this time" << std::endl;
}

Input::Event *SDL::Console::next_event()
{
  Prague::Trace trace("SDL::Console::next_event()");

  SDL_Event event;
  SDL_WaitEvent(&event);
  return synthesize(event);
}

void SDL::Console::wakeup()
{
  Prague::Trace trace("SDL::Console::wakeup()");

  char c = 'z'; write(_wakeupPipe[1],&c,1);
}

Input::Event *SDL::Console::synthesize(const SDL_Event &e)
{
  Prague::Trace trace("SDL::Console::synthesize()");

  Input::Event_var event = new Input::Event;
  switch (e.type)
    {
    case SDL_KEYDOWN:
      {
	Input::Toggle toggle;
	toggle.actuation = Input::Toggle::press;
	toggle.number = e.key.keysym.unicode;
	event->length(1);
	event[0].dev = 0;
	event[0].attr.selection(toggle); event[0].attr._d(Input::key);
	break;
      }
    case SDL_MOUSEMOTION:
      {
	// grab waiting mouse events and skip to the last one
	SDL_Event move_events[64];
	SDL_PumpEvents();
	int num = SDL_PeepEvents(move_events, 64, SDL_GETEVENT, SDL_MOUSEMOTIONMASK);
	if (num > 0)
	  {
	    // Use last known position of mouse
	    _position[0] = move_events[num-1].motion.x;
	    _position[1] = move_events[num-1].motion.y;
	  }
	else
	  {
	    // Use position from original event
	    _position[0] = e.motion.x;
	    _position[1] = e.motion.y;
	  }
	Input::Position position;
	position.x = _position[0]/_resolution[0];
	position.y = _position[1]/_resolution[1];
	position.z = 0;
	event->length(1);
	event[0].dev = 1;
	event[0].attr.location(position);
	break;
      }
    case SDL_MOUSEBUTTONDOWN:
    case SDL_MOUSEBUTTONUP:
      {
	Input::Toggle toggle;
	if (e.type == SDL_MOUSEBUTTONDOWN)
	  toggle.actuation = Input::Toggle::press;
	else
	  toggle.actuation = Input::Toggle::release;
	toggle.number = e.button.button;
	Input::Position position;
	position.x = _position[0]/_resolution[0];
	position.y = _position[1]/_resolution[1];
	position.z = 0;
	event->length(2);
	event[0].dev = 1;
	event[0].attr.selection(toggle); event[0].attr._d(Input::button);
	event[1].dev = 1;
	event[1].attr.location(position);
	break;
      }
    case SDL_QUIT:
      {
	// this is a CTRL+C sent to the controlling terminal. Berlin may be
	// already crashed, so terminate forcibly.
	exit(0);
	break;
      }
    }

  return event._retn();
}

void SDL::Console::set_PointerManager(PointerManager * pm) {
  _pointer_mgr = pm;
}

Console::Extension * SDL::Console::create_extension(const std::string & id)
{
  Prague::Trace trace("SDL::Console::create_extension()");

  if (id == "Renderer")
    return new SDL::Renderer();
  if (id == "GLContext") {
    Prague::Path path = RCManager::get_path("modulepath");
    std::string name = path.lookup_file("Console/SDLGL.so");
    Prague::Plugin<Extension> * plugin = 0;
    if (name.empty())
      {
	std::string msg =
	  "GLContext extension for SDL console not found in modulepath.";
	throw std::runtime_error(msg);
      }
    else {
      plugin = new Prague::Plugin<Extension>(name);
      _modules.push_back(plugin);
      _is_gl = 1;
      return plugin->get();
    }
  }
  if (id == "DirectBuffer")
    return new SDL::DirectBuffer();
  return 0;
}

// ---------------------------------------------------------------
// externs
// ---------------------------------------------------------------

extern "C" ::Console::LoaderT<SDL::Console> *load() { return new Console::LoaderT<SDL::Console>(); }
<|endoftext|>


<commit_before>#include "Codec_repetition.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Codec_repetition::name   = "Codec Repetition";
const std::string aff3ct::factory::Codec_repetition::prefix = "cdc";

Codec_repetition::parameters
::parameters(const std::string prefix)
: Codec     ::parameters(Codec_repetition::name, prefix),
  Codec_SIHO::parameters(Codec_repetition::name, prefix),
  enc(new Encoder_repetition::parameters("enc")),
  dec(new Decoder_repetition::parameters("dec"))
{
	Codec::parameters::enc = enc;
	Codec::parameters::dec = dec;
}

Codec_repetition::parameters
::~parameters()
{
	if (enc != nullptr) { delete enc; enc = nullptr; }
	if (dec != nullptr) { delete dec; dec = nullptr; }

	Codec::parameters::enc = nullptr;
	Codec::parameters::dec = nullptr;
}

Codec_repetition::parameters* Codec_repetition::parameters
::clone() const
{
	auto clone = new Codec_repetition::parameters(*this);

	if (enc != nullptr) { clone->enc = enc->clone(); }
	if (dec != nullptr) { clone->dec = dec->clone(); }

	clone->set_enc(clone->enc);
	clone->set_dec(clone->dec);

	return clone;
}

void Codec_repetition::parameters
::get_description(arg_map &req_args, arg_map &opt_args) const
{
	Codec_SIHO::parameters::get_description(req_args, opt_args);

	enc->get_description(req_args, opt_args);
	dec->get_description(req_args, opt_args);

	auto pdec = dec->get_prefix();

	req_args.erase({pdec+"-cw-size",   "N"});
	req_args.erase({pdec+"-info-bits", "K"});
	opt_args.erase({pdec+"-fra",       "F"});
}

void Codec_repetition::parameters
::store(const arg_val_map &vals)
{
	Codec_SIHO::parameters::store(vals);

	enc->store(vals);

	this->dec->K        = this->enc->K;
	this->dec->N_cw     = this->enc->N_cw;
	this->dec->n_frames = this->enc->n_frames;

	dec->store(vals);

	this->K    = this->enc->K;
	this->N_cw = this->enc->N_cw;
	this->N    = this->enc->N_cw;
}

void Codec_repetition::parameters
::get_headers(std::map<std::string,header_list>& headers, const bool full) const
{
	Codec_SIHO::parameters::get_headers(headers, full);

	enc->get_headers(headers, full);
	dec->get_headers(headers, full);
}

template <typename B, typename Q>
module::Codec_repetition<B,Q>* Codec_repetition::parameters
::build(module::CRC<B> *crc) const
{
	return new module::Codec_repetition<B,Q>(*enc, *dec);

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__);
}

template <typename B, typename Q>
module::Codec_repetition<B,Q>* Codec_repetition
::build(const parameters &params, module::CRC<B> *crc)
{
	return params.template build<B,Q>();
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::module::Codec_repetition<B_8 ,Q_8 >* aff3ct::factory::Codec_repetition::parameters::build<B_8 ,Q_8 >(aff3ct::module::CRC<B_8 >*) const;
template aff3ct::module::Codec_repetition<B_16,Q_16>* aff3ct::factory::Codec_repetition::parameters::build<B_16,Q_16>(aff3ct::module::CRC<B_16>*) const;
template aff3ct::module::Codec_repetition<B_32,Q_32>* aff3ct::factory::Codec_repetition::parameters::build<B_32,Q_32>(aff3ct::module::CRC<B_32>*) const;
template aff3ct::module::Codec_repetition<B_64,Q_64>* aff3ct::factory::Codec_repetition::parameters::build<B_64,Q_64>(aff3ct::module::CRC<B_64>*) const;
template aff3ct::module::Codec_repetition<B_8 ,Q_8 >* aff3ct::factory::Codec_repetition::build<B_8 ,Q_8 >(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_8 >*);
template aff3ct::module::Codec_repetition<B_16,Q_16>* aff3ct::factory::Codec_repetition::build<B_16,Q_16>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_16>*);
template aff3ct::module::Codec_repetition<B_32,Q_32>* aff3ct::factory::Codec_repetition::build<B_32,Q_32>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_32>*);
template aff3ct::module::Codec_repetition<B_64,Q_64>* aff3ct::factory::Codec_repetition::build<B_64,Q_64>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_64>*);
#else
template aff3ct::module::Codec_repetition<B,Q>* aff3ct::factory::Codec_repetition::parameters::build<B,Q>(aff3ct::module::CRC<B>*) const;
template aff3ct::module::Codec_repetition<B,Q>* aff3ct::factory::Codec_repetition::build<B,Q>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B>*);
#endif
// ==================================================================================== explicit template instantiation
<commit_msg>Fix rep buffered param.<commit_after>#include "Codec_repetition.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Codec_repetition::name   = "Codec Repetition";
const std::string aff3ct::factory::Codec_repetition::prefix = "cdc";

Codec_repetition::parameters
::parameters(const std::string prefix)
: Codec     ::parameters(Codec_repetition::name, prefix),
  Codec_SIHO::parameters(Codec_repetition::name, prefix),
  enc(new Encoder_repetition::parameters("enc")),
  dec(new Decoder_repetition::parameters("dec"))
{
	Codec::parameters::enc = enc;
	Codec::parameters::dec = dec;
}

Codec_repetition::parameters
::~parameters()
{
	if (enc != nullptr) { delete enc; enc = nullptr; }
	if (dec != nullptr) { delete dec; dec = nullptr; }

	Codec::parameters::enc = nullptr;
	Codec::parameters::dec = nullptr;
}

Codec_repetition::parameters* Codec_repetition::parameters
::clone() const
{
	auto clone = new Codec_repetition::parameters(*this);

	if (enc != nullptr) { clone->enc = enc->clone(); }
	if (dec != nullptr) { clone->dec = dec->clone(); }

	clone->set_enc(clone->enc);
	clone->set_dec(clone->dec);

	return clone;
}

void Codec_repetition::parameters
::get_description(arg_map &req_args, arg_map &opt_args) const
{
	Codec_SIHO::parameters::get_description(req_args, opt_args);

	enc->get_description(req_args, opt_args);
	dec->get_description(req_args, opt_args);

	auto pdec = dec->get_prefix();

	req_args.erase({pdec+"-cw-size",   "N"});
	req_args.erase({pdec+"-info-bits", "K"});
	opt_args.erase({pdec+"-no-buff"       });
	opt_args.erase({pdec+"-fra",       "F"});
}

void Codec_repetition::parameters
::store(const arg_val_map &vals)
{
	Codec_SIHO::parameters::store(vals);

	enc->store(vals);

	this->dec->K        = this->enc->K;
	this->dec->N_cw     = this->enc->N_cw;
	this->dec->buffered = this->enc->buffered;
	this->dec->n_frames = this->enc->n_frames;

	dec->store(vals);

	this->K    = this->enc->K;
	this->N_cw = this->enc->N_cw;
	this->N    = this->enc->N_cw;
}

void Codec_repetition::parameters
::get_headers(std::map<std::string,header_list>& headers, const bool full) const
{
	Codec_SIHO::parameters::get_headers(headers, full);

	enc->get_headers(headers, full);
	dec->get_headers(headers, full);
}

template <typename B, typename Q>
module::Codec_repetition<B,Q>* Codec_repetition::parameters
::build(module::CRC<B> *crc) const
{
	return new module::Codec_repetition<B,Q>(*enc, *dec);

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__);
}

template <typename B, typename Q>
module::Codec_repetition<B,Q>* Codec_repetition
::build(const parameters &params, module::CRC<B> *crc)
{
	return params.template build<B,Q>();
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::module::Codec_repetition<B_8 ,Q_8 >* aff3ct::factory::Codec_repetition::parameters::build<B_8 ,Q_8 >(aff3ct::module::CRC<B_8 >*) const;
template aff3ct::module::Codec_repetition<B_16,Q_16>* aff3ct::factory::Codec_repetition::parameters::build<B_16,Q_16>(aff3ct::module::CRC<B_16>*) const;
template aff3ct::module::Codec_repetition<B_32,Q_32>* aff3ct::factory::Codec_repetition::parameters::build<B_32,Q_32>(aff3ct::module::CRC<B_32>*) const;
template aff3ct::module::Codec_repetition<B_64,Q_64>* aff3ct::factory::Codec_repetition::parameters::build<B_64,Q_64>(aff3ct::module::CRC<B_64>*) const;
template aff3ct::module::Codec_repetition<B_8 ,Q_8 >* aff3ct::factory::Codec_repetition::build<B_8 ,Q_8 >(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_8 >*);
template aff3ct::module::Codec_repetition<B_16,Q_16>* aff3ct::factory::Codec_repetition::build<B_16,Q_16>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_16>*);
template aff3ct::module::Codec_repetition<B_32,Q_32>* aff3ct::factory::Codec_repetition::build<B_32,Q_32>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_32>*);
template aff3ct::module::Codec_repetition<B_64,Q_64>* aff3ct::factory::Codec_repetition::build<B_64,Q_64>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B_64>*);
#else
template aff3ct::module::Codec_repetition<B,Q>* aff3ct::factory::Codec_repetition::parameters::build<B,Q>(aff3ct::module::CRC<B>*) const;
template aff3ct::module::Codec_repetition<B,Q>* aff3ct::factory::Codec_repetition::build<B,Q>(const aff3ct::factory::Codec_repetition::parameters&, aff3ct::module::CRC<B>*);
#endif
// ==================================================================================== explicit template instantiation
<|endoftext|>


<commit_before>/* logs.cc
   Eric Robert, 9 October 2013
   Copyright (c) 2013 Datacratic.  All rights reserved.

   Basic logs
*/

#include "soa/service/logs.h"
#include "jml/utils/exc_check.h"

#include <iostream>
#include <mutex>
#include <unordered_map>
#include <vector>

namespace Datacratic {

void Logging::ConsoleWriter::head(char const * timestamp,
                                  char const * name,
                                  char const * function,
                                  char const * file,
                                  int line) {
    if(color) {
        stream << timestamp << " " << "\033[1;32m" << name << " ";
    }
    else {
        stream << timestamp << " " << name << " ";
    }
}

void Logging::ConsoleWriter::body(std::string const & content) {
    if(color) {
        stream << "\033[1;34m";
        stream.write(content.c_str(), content.size() - 1);
        stream << "\033[0m\n";
    }
    else {
        stream << content;
    }

    std::cerr << stream.str();
    stream.str("");
}

void Logging::FileWriter::head(char const * timestamp,
                               char const * name,
                               char const * function,
                               char const * file,
                               int line) {
    stream << timestamp << " " << name << " ";
}

void Logging::FileWriter::body(std::string const & content) {
    file << stream.str() << content;
    stream.str("");
}

void Logging::FileWriter::open(char const * filename, char const mode) {
    if(mode == 'a')
        file.open(filename, std::ofstream::app);
    else if (mode == 'w')
        file.open(filename);
    else
        throw ML::Exception("File mode not recognized");

    if(!file) {
        std::cerr << "unable to open log file '" << filename << "'" << std::endl;
    }
}

void Logging::JsonWriter::head(char const * timestamp,
                               char const * name,
                               char const * function,
                               char const * file,
                               int line) {
    stream << "{\"time\":\"" << timestamp
           << "\",\"name\":\"" << name
           << "\",\"call\":\"" << function
           << "\",\"file\":\"" << file
           << "\",\"line\":" << line
           << ",\"text\":\"";
}

void Logging::JsonWriter::body(std::string const & content) {
    stream.write(content.c_str(), content.size() - 1);
    stream << "\"}\n";
    if(!writer) {
        std::cerr << stream.str();
    }
    else {
        writer->body(stream.str());
    }

    stream.str("");
}

namespace {

struct Registry {
    std::mutex lock;
    std::unordered_map<std::string, std::unique_ptr<Logging::CategoryData> > categories;
};

Registry& getRegistry() {
    // Will leak but that's on program exit so who cares.
    static Registry* registry = new Registry;

    return *registry;
}

} // namespace anonymous

struct Logging::CategoryData {
    bool initialized;
    bool enabled;
    char const * name;
    std::shared_ptr<Writer> writer;
    std::stringstream stream;

    CategoryData * parent;
    std::vector<CategoryData *> children;

    static CategoryData * getRoot();
    static CategoryData * get(char const * name);

    static CategoryData * create(char const * name, char const * super, bool enabled);
    static void destroy(CategoryData * name);

    void activate(bool recurse = true);
    void deactivate(bool recurse = true);
    void writeTo(std::shared_ptr<Writer> output, bool recurse = true);

private:

    CategoryData(char const * name, bool enabled) :
        initialized(false),
        enabled(enabled),
        name(name),
        parent(nullptr) {
    }

};

Logging::CategoryData * Logging::CategoryData::get(char const * name) {
    Registry& registry = getRegistry();

    auto it = registry.categories.find(name);
    return it != registry.categories.end() ? it->second.get() : nullptr;
}

Logging::CategoryData * Logging::CategoryData::getRoot() {
    CategoryData * root = get("*");
    if (root) return root;

    getRegistry().categories["*"].reset(root = new CategoryData("*", true /* enabled */));
    root->parent = root;
    root->writer = std::make_shared<ConsoleWriter>();

    return root;
}

Logging::CategoryData * Logging::CategoryData::create(char const * name, char const * super, bool enabled) {
    Registry& registry = getRegistry();
    std::lock_guard<std::mutex> guard(registry.lock);

    CategoryData * root = getRoot();
    CategoryData * data = get(name);

    if (!data) {
        registry.categories[name].reset(data = new CategoryData(name, enabled));
    }
    else {
        ExcCheck(!data->initialized,
                "making duplicate category: " + std::string(name));
    }

    data->initialized = true;

    data->parent = get(super);
    if (!data->parent) {
        registry.categories[super].reset(data->parent = new CategoryData(super, enabled));
    }

    data->parent->children.push_back(data);

    if (data->parent->initialized) {
        data->writer = data->parent->writer;
    }
    else {
        data->writer = root->writer;
    }

    return data;
}

void Logging::CategoryData::destroy(CategoryData * data) {
    if (data->parent == data) return;

    Registry& registry = getRegistry();
    std::string name = data->name;

    std::lock_guard<std::mutex> guard(registry.lock);

    auto dataIt = registry.categories.find(name);
    ExcCheck(dataIt != registry.categories.end(),
            "double destroy of a category: " + name);

    auto& children = data->parent->children;

    auto childIt = std::find(children.begin(), children.end(), data);
    if (childIt != children.end()) {
        children.erase(childIt);
    }

    CategoryData* root = getRoot();
    for (auto& child : data->children) {
        child->parent = root;
    }

    registry.categories.erase(dataIt);
}

void Logging::CategoryData::activate(bool recurse) {
    enabled = true;
    if(recurse) {
        for(auto item : children) {
            item->activate(recurse);
        }
    }
}

void Logging::CategoryData::deactivate(bool recurse) {
    enabled = false;
    if(recurse) {
        for(auto item : children) {
            item->deactivate(recurse);
        }
    }
}

void Logging::CategoryData::writeTo(std::shared_ptr<Writer> output, bool recurse) {
    writer = output;
    if(recurse) {
        for(auto item : children) {
            item->writeTo(output, recurse);
        }
    }
}

Logging::Category& Logging::Category::root() {
    static Category root(CategoryData::getRoot());
    return root;
}

Logging::Category::Category(CategoryData * data) :
    data(data) {
}

Logging::Category::Category(char const * name, Category & super, bool enabled) :
    data(CategoryData::create(name, super.name(), enabled)) {
}

Logging::Category::Category(char const * name, char const * super, bool enabled) :
    data(CategoryData::create(name, super, enabled)) {
}

Logging::Category::Category(char const * name, bool enabled) :
    data(CategoryData::create(name, "*", enabled)) {
}

Logging::Category::~Category()
{
    CategoryData::destroy(data);
}

char const * Logging::Category::name() const {
    return data->name;
}

bool Logging::Category::isEnabled() const {
    return data->enabled;
}

bool Logging::Category::isDisabled() const {
    return !data->enabled;
}

auto Logging::Category::getWriter() const -> std::shared_ptr<Writer> const &
{
    return data->writer;
}

void Logging::Category::activate(bool recurse) {
    data->activate(recurse);
}

void Logging::Category::deactivate(bool recurse) {
    data->deactivate(recurse);
}

void Logging::Category::writeTo(std::shared_ptr<Writer> output, bool recurse) {
    data->writeTo(output, recurse);
}

std::ostream & Logging::Category::beginWrite(char const * fct, char const * file, int line) {
    timeval now;
    gettimeofday(&now, 0);
    char text[64];
    auto count = strftime(text, sizeof(text), "%Y-%m-%d %H:%M:%S", localtime(&now.tv_sec));
    int ms = now.tv_usec / 1000;
    sprintf(text + count, ".%03d", ms);
    data->writer->head(text, data->name, fct, file, line);
    return data->stream;
}

void Logging::Printer::operator&(std::ostream & stream) {
    std::stringstream & text = (std::stringstream &) stream;
    category.getWriter()->body(text.str());
    text.str("");
}

void Logging::Thrower::operator&(std::ostream & stream) {
    std::stringstream & text = (std::stringstream &) stream;
    std::string message(text.str());
    text.str("");
    throw ML::Exception(message);
}

} // namespace Datacratic
<commit_msg>hotfix for memory corruption caused by using a logging category from multiple threads.<commit_after>/* logs.cc
   Eric Robert, 9 October 2013
   Copyright (c) 2013 Datacratic.  All rights reserved.

   Basic logs
*/

#include "soa/service/logs.h"
#include "jml/utils/exc_check.h"

#include <iostream>
#include <mutex>
#include <unordered_map>
#include <vector>

namespace Datacratic {

void Logging::ConsoleWriter::head(char const * timestamp,
                                  char const * name,
                                  char const * function,
                                  char const * file,
                                  int line) {
    if(color) {
        stream << timestamp << " " << "\033[1;32m" << name << " ";
    }
    else {
        stream << timestamp << " " << name << " ";
    }
}

void Logging::ConsoleWriter::body(std::string const & content) {
    if(color) {
        stream << "\033[1;34m";
        stream.write(content.c_str(), content.size() - 1);
        stream << "\033[0m\n";
    }
    else {
        stream << content;
    }

    std::cerr << stream.str();
    stream.str("");
}

void Logging::FileWriter::head(char const * timestamp,
                               char const * name,
                               char const * function,
                               char const * file,
                               int line) {
    stream << timestamp << " " << name << " ";
}

void Logging::FileWriter::body(std::string const & content) {
    file << stream.str() << content;
    stream.str("");
}

void Logging::FileWriter::open(char const * filename, char const mode) {
    if(mode == 'a')
        file.open(filename, std::ofstream::app);
    else if (mode == 'w')
        file.open(filename);
    else
        throw ML::Exception("File mode not recognized");

    if(!file) {
        std::cerr << "unable to open log file '" << filename << "'" << std::endl;
    }
}

void Logging::JsonWriter::head(char const * timestamp,
                               char const * name,
                               char const * function,
                               char const * file,
                               int line) {
    stream << "{\"time\":\"" << timestamp
           << "\",\"name\":\"" << name
           << "\",\"call\":\"" << function
           << "\",\"file\":\"" << file
           << "\",\"line\":" << line
           << ",\"text\":\"";
}

void Logging::JsonWriter::body(std::string const & content) {
    stream.write(content.c_str(), content.size() - 1);
    stream << "\"}\n";
    if(!writer) {
        std::cerr << stream.str();
    }
    else {
        writer->body(stream.str());
    }

    stream.str("");
}

namespace {

struct Registry {
    std::mutex lock;
    std::unordered_map<std::string, std::unique_ptr<Logging::CategoryData> > categories;
};

Registry& getRegistry() {
    // Will leak but that's on program exit so who cares.
    static Registry* registry = new Registry;

    return *registry;
}

} // namespace anonymous

struct Logging::CategoryData {
    bool initialized;
    bool enabled;
    char const * name;
    std::shared_ptr<Writer> writer;
    std::stringstream stream;

    CategoryData * parent;
    std::vector<CategoryData *> children;

    static CategoryData * getRoot();
    static CategoryData * get(char const * name);

    static CategoryData * create(char const * name, char const * super, bool enabled);
    static void destroy(CategoryData * name);

    void activate(bool recurse = true);
    void deactivate(bool recurse = true);
    void writeTo(std::shared_ptr<Writer> output, bool recurse = true);

private:

    CategoryData(char const * name, bool enabled) :
        initialized(false),
        enabled(enabled),
        name(name),
        parent(nullptr) {
    }

};

Logging::CategoryData * Logging::CategoryData::get(char const * name) {
    Registry& registry = getRegistry();

    auto it = registry.categories.find(name);
    return it != registry.categories.end() ? it->second.get() : nullptr;
}

Logging::CategoryData * Logging::CategoryData::getRoot() {
    CategoryData * root = get("*");
    if (root) return root;

    getRegistry().categories["*"].reset(root = new CategoryData("*", true /* enabled */));
    root->parent = root;
    root->writer = std::make_shared<ConsoleWriter>();

    return root;
}

Logging::CategoryData * Logging::CategoryData::create(char const * name, char const * super, bool enabled) {
    Registry& registry = getRegistry();
    std::lock_guard<std::mutex> guard(registry.lock);

    CategoryData * root = getRoot();
    CategoryData * data = get(name);

    if (!data) {
        registry.categories[name].reset(data = new CategoryData(name, enabled));
    }
    else {
        ExcCheck(!data->initialized,
                "making duplicate category: " + std::string(name));
    }

    data->initialized = true;

    data->parent = get(super);
    if (!data->parent) {
        registry.categories[super].reset(data->parent = new CategoryData(super, enabled));
    }

    data->parent->children.push_back(data);

    if (data->parent->initialized) {
        data->writer = data->parent->writer;
    }
    else {
        data->writer = root->writer;
    }

    return data;
}

void Logging::CategoryData::destroy(CategoryData * data) {
    if (data->parent == data) return;

    Registry& registry = getRegistry();
    std::string name = data->name;

    std::lock_guard<std::mutex> guard(registry.lock);

    auto dataIt = registry.categories.find(name);
    ExcCheck(dataIt != registry.categories.end(),
            "double destroy of a category: " + name);

    auto& children = data->parent->children;

    auto childIt = std::find(children.begin(), children.end(), data);
    if (childIt != children.end()) {
        children.erase(childIt);
    }

    CategoryData* root = getRoot();
    for (auto& child : data->children) {
        child->parent = root;
    }

    registry.categories.erase(dataIt);
}

void Logging::CategoryData::activate(bool recurse) {
    enabled = true;
    if(recurse) {
        for(auto item : children) {
            item->activate(recurse);
        }
    }
}

void Logging::CategoryData::deactivate(bool recurse) {
    enabled = false;
    if(recurse) {
        for(auto item : children) {
            item->deactivate(recurse);
        }
    }
}

void Logging::CategoryData::writeTo(std::shared_ptr<Writer> output, bool recurse) {
    writer = output;
    if(recurse) {
        for(auto item : children) {
            item->writeTo(output, recurse);
        }
    }
}

Logging::Category& Logging::Category::root() {
    static Category root(CategoryData::getRoot());
    return root;
}

Logging::Category::Category(CategoryData * data) :
    data(data) {
}

Logging::Category::Category(char const * name, Category & super, bool enabled) :
    data(CategoryData::create(name, super.name(), enabled)) {
}

Logging::Category::Category(char const * name, char const * super, bool enabled) :
    data(CategoryData::create(name, super, enabled)) {
}

Logging::Category::Category(char const * name, bool enabled) :
    data(CategoryData::create(name, "*", enabled)) {
}

Logging::Category::~Category()
{
    CategoryData::destroy(data);
}

char const * Logging::Category::name() const {
    return data->name;
}

bool Logging::Category::isEnabled() const {
    return data->enabled;
}

bool Logging::Category::isDisabled() const {
    return !data->enabled;
}

auto Logging::Category::getWriter() const -> std::shared_ptr<Writer> const &
{
    return data->writer;
}

void Logging::Category::activate(bool recurse) {
    data->activate(recurse);
}

void Logging::Category::deactivate(bool recurse) {
    data->deactivate(recurse);
}

void Logging::Category::writeTo(std::shared_ptr<Writer> output, bool recurse) {
    data->writeTo(output, recurse);
}

// This lock is a quick-fix for the case where a category is used by multiple
// threads. Note that this lock should either eventually be removed or replaced
// by a per category lock. Unfortunately the current setup makes it very
// difficult to pass the header information to the operator& so that everything
// can be dumped in the stream in one go.
namespace { std::mutex loggingMutex; }

std::ostream & Logging::Category::beginWrite(char const * fct, char const * file, int line) {
    loggingMutex.lock();

    timeval now;
    gettimeofday(&now, 0);
    char text[64];
    auto count = strftime(text, sizeof(text), "%Y-%m-%d %H:%M:%S", localtime(&now.tv_sec));
    int ms = now.tv_usec / 1000;
    sprintf(text + count, ".%03d", ms);
    data->writer->head(text, data->name, fct, file, line);
    return data->stream;
}

void Logging::Printer::operator&(std::ostream & stream) {
    std::stringstream & text = (std::stringstream &) stream;
    category.getWriter()->body(text.str());
    text.str("");

    loggingMutex.unlock();
}

void Logging::Thrower::operator&(std::ostream & stream) {
    std::stringstream & text = (std::stringstream &) stream;
    std::string message(text.str());
    text.str("");
    loggingMutex.unlock();

    throw ML::Exception(message);
}

} // namespace Datacratic
<|endoftext|>


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

/**
 * @file qp_spline_st_graph.cc
 **/

#include "modules/planning/optimizer/qp_spline_st_speed/qp_spline_st_graph.h"

#include <algorithm>
#include <string>
#include <utility>

#include "modules/common/log.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::VehicleParam;

QpSplineStGraph::QpSplineStGraph(
    const QpSplineStSpeedConfig& qp_spline_st_speed_config,
    const apollo::common::VehicleParam& veh_param)
    : qp_spline_st_speed_config_(qp_spline_st_speed_config),
      time_resolution_(
          qp_spline_st_speed_config_.total_time() /
          qp_spline_st_speed_config_.number_of_discrete_graph_t()) {}

void QpSplineStGraph::Init() {
  double curr_t = 0.0;
  for (uint32_t i = 0;
       i <= qp_spline_st_speed_config_.number_of_discrete_graph_t(); ++i) {
    t_knots_.push_back(curr_t);
    curr_t += time_resolution_;
  }
  spline_generator_.reset(new Spline1dGenerator(
      t_knots_, qp_spline_st_speed_config_.spline_order()));
}

Status QpSplineStGraph::Search(const StGraphData& st_graph_data,
                               const PathData& path_data,
                               SpeedData* const speed_data) {
  init_point_ = st_graph_data.init_point();
  if (st_graph_data.path_data_length() <
      qp_spline_st_speed_config_.total_path_length()) {
    qp_spline_st_speed_config_.set_total_path_length(
        st_graph_data.path_data_length());
  }

  // TODO(all): update speed limit here
  // TODO(all): update config through veh physical limit here generate knots

  // initialize time resolution and
  Init();

  if (!ApplyConstraint(st_graph_data.obs_boundary()).ok()) {
    const std::string msg = "Apply constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!ApplyKernel(st_graph_data.speed_limit()).ok()) {
    const std::string msg = "Apply kernel failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!Solve().ok()) {
    const std::string msg = "Solve qp problem failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // extract output
  speed_data->Clear();
  const Spline1d& spline = spline_generator_->spline();

  double time_resolution = qp_spline_st_speed_config_.output_time_resolution();
  double time = 0.0;
  while (time < qp_spline_st_speed_config_.total_time() + time_resolution) {
    double s = spline(time);
    double v = spline.derivative(time);
    double a = spline.second_order_derivative(time);
    double da = spline.third_order_derivative(time);
    speed_data->add_speed_point(s, time, v, a, da);
    time += time_resolution;
  }

  return Status::OK();
}

Status QpSplineStGraph::ApplyConstraint(
    const std::vector<StGraphBoundary>& boundaries) {
  Spline1dConstraint* constraint =
      spline_generator_->mutable_spline_constraint();
  // position, velocity, acceleration

  if (!constraint->add_point_fx_constraint(0.0, 0.0)) {
    const std::string msg = "add st start point constraint failed";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!constraint->add_point_derivative_constraint(0.0, init_point_.v())) {
    const std::string msg = "add st start point velocity constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!constraint->add_point_second_derivative_constraint(0.0,
                                                          init_point_.a())) {
    const std::string msg =
        "add st start point acceleration constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!constraint->add_point_second_derivative_constraint(
          spline_generator_->spline().x_knots().back(), 0.0)) {
    const std::string msg = "add st end point acceleration constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // monotone constraint
  if (!constraint->add_monotone_fx_inequality_constraint_at_knots()) {
    const std::string msg = "add monotonicity constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // smoothness constraint
  if (!constraint->add_third_derivative_smooth_constraint()) {
    const std::string msg = "add smoothness joint constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // boundary constraint
  std::vector<double> s_upper_bound;
  std::vector<double> s_lower_bound;

  for (const double curr_t : t_knots_) {
    double lower_s = 0.0;
    double upper_s = 0.0;
    GetSConstraintByTime(boundaries, curr_t,
                         qp_spline_st_speed_config_.total_path_length(),
                         &upper_s, &lower_s);
    s_upper_bound.push_back(upper_s);
    s_lower_bound.push_back(lower_s);
  }
  if (!constraint->add_fx_boundary(t_knots_, s_lower_bound, s_upper_bound)) {
    const std::string msg = "Fail to apply obstacle constraint";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  // TODO(Liangliang):
  // add speed constraint and other limits according to adu/planning
  return Status::OK();
}

Status QpSplineStGraph::ApplyKernel(const SpeedLimit& speed_limit) {
  Spline1dKernel* spline_kernel = spline_generator_->mutable_spline_kernel();

  if (qp_spline_st_speed_config_.speed_kernel_weight() > 0) {
    spline_kernel->add_derivative_kernel_matrix(
        qp_spline_st_speed_config_.speed_kernel_weight());
  }

  if (qp_spline_st_speed_config_.accel_kernel_weight() > 0) {
    spline_kernel->add_second_order_derivative_matrix(
        qp_spline_st_speed_config_.accel_kernel_weight());
  }

  if (qp_spline_st_speed_config_.jerk_kernel_weight() > 0) {
    spline_kernel->add_third_order_derivative_matrix(
        qp_spline_st_speed_config_.jerk_kernel_weight());
  }

  // TODO(all): add reference speed profile for different main decision
  std::vector<double> s_vec;
  if (speed_limit.speed_limits().size() == 0) {
    return Status(ErrorCode::PLANNING_ERROR,
                  "Fail to apply_kernel due to empty speed limits.");
  }
  double dist_ref = 0.0;
  for (uint32_t i = 0;
       i <= qp_spline_st_speed_config_.number_of_discrete_graph_t(); ++i) {
    s_vec.push_back(dist_ref);
    dist_ref += time_resolution_ * speed_limit.get_speed_limit(dist_ref);
  }
  // TODO: change reference line kernel to configurable version
  spline_kernel->add_reference_line_kernel_matrix(t_knots_, s_vec, 1);
  return Status::OK();
}

Status QpSplineStGraph::Solve() {
  return spline_generator_->solve()
             ? Status::OK()
             : Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::solve");
}

Status QpSplineStGraph::AddFollowReferenceLineKernel(
    const StGraphBoundary& follow_boundary) {
  if (follow_boundary.boundary_type() !=
      StGraphBoundary::BoundaryType::FOLLOW) {
    std::string msg = common::util::StrCat(
        "Fail to add follow reference line kernel because boundary type is ",
        "incorrect. type: ", static_cast<int>(follow_boundary.boundary_type()),
        ".");
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  auto* spline_kernel = spline_generator_->mutable_spline_kernel();
  std::vector<double> ref_s;
  for (const double curr_t : t_knots_) {
    double s_upper = 0.0;
    double s_lower = 0.0;
    if (follow_boundary.get_s_boundary_position(curr_t, &s_upper, &s_lower)) {
      ref_s.push_back(s_upper - follow_boundary.characteristic_length());
    }
    ref_s.push_back(s_upper);
  }

  spline_kernel->add_reference_line_kernel_matrix(t_knots_, ref_s, 1.0);
  return Status::OK();
}

Status QpSplineStGraph::GetSConstraintByTime(
    const std::vector<StGraphBoundary>& boundaries, const double time,
    const double total_path_s, double* const s_upper_bound,
    double* const s_lower_bound) const {
  *s_upper_bound =
      std::min(total_path_s, time * qp_spline_st_speed_config_.max_speed());

  for (const StGraphBoundary& boundary : boundaries) {
    double s_upper = 0.0;
    double s_lower = 0.0;

    if (!boundary.get_s_boundary_position(time, &s_upper, &s_lower)) {
      continue;
    }

    if (boundary.boundary_type() == StGraphBoundary::BoundaryType::STOP ||
        boundary.boundary_type() == StGraphBoundary::BoundaryType::FOLLOW ||
        boundary.boundary_type() == StGraphBoundary::BoundaryType::YIELD) {
      *s_upper_bound = std::fmin(*s_upper_bound, s_upper);
    } else {
      *s_lower_bound = std::fmax(*s_lower_bound, s_lower);
    }
  }

  return Status::OK();
}
}  // namespace planning
}  // namespace apollo
<commit_msg>used follow boundary reference line<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file qp_spline_st_graph.cc
 **/

#include "modules/planning/optimizer/qp_spline_st_speed/qp_spline_st_graph.h"

#include <algorithm>
#include <string>
#include <utility>

#include "modules/common/log.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::VehicleParam;

QpSplineStGraph::QpSplineStGraph(
    const QpSplineStSpeedConfig& qp_spline_st_speed_config,
    const apollo::common::VehicleParam& veh_param)
    : qp_spline_st_speed_config_(qp_spline_st_speed_config),
      time_resolution_(
          qp_spline_st_speed_config_.total_time() /
          qp_spline_st_speed_config_.number_of_discrete_graph_t()) {}

void QpSplineStGraph::Init() {
  double curr_t = 0.0;
  for (uint32_t i = 0;
       i <= qp_spline_st_speed_config_.number_of_discrete_graph_t(); ++i) {
    t_knots_.push_back(curr_t);
    curr_t += time_resolution_;
  }
  spline_generator_.reset(new Spline1dGenerator(
      t_knots_, qp_spline_st_speed_config_.spline_order()));
}

Status QpSplineStGraph::Search(const StGraphData& st_graph_data,
                               const PathData& path_data,
                               SpeedData* const speed_data) {
  init_point_ = st_graph_data.init_point();
  if (st_graph_data.path_data_length() <
      qp_spline_st_speed_config_.total_path_length()) {
    qp_spline_st_speed_config_.set_total_path_length(
        st_graph_data.path_data_length());
  }

  // TODO(all): update speed limit here
  // TODO(all): update config through veh physical limit here generate knots

  // initialize time resolution and
  Init();

  if (!ApplyConstraint(st_graph_data.obs_boundary()).ok()) {
    const std::string msg = "Apply constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!ApplyKernel(st_graph_data.speed_limit()).ok()) {
    const std::string msg = "Apply kernel failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!Solve().ok()) {
    const std::string msg = "Solve qp problem failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // extract output
  speed_data->Clear();
  const Spline1d& spline = spline_generator_->spline();

  double time_resolution = qp_spline_st_speed_config_.output_time_resolution();
  double time = 0.0;
  while (time < qp_spline_st_speed_config_.total_time() + time_resolution) {
    double s = spline(time);
    double v = spline.derivative(time);
    double a = spline.second_order_derivative(time);
    double da = spline.third_order_derivative(time);
    speed_data->add_speed_point(s, time, v, a, da);
    time += time_resolution;
  }

  return Status::OK();
}

Status QpSplineStGraph::ApplyConstraint(
    const std::vector<StGraphBoundary>& boundaries) {
  Spline1dConstraint* constraint =
      spline_generator_->mutable_spline_constraint();
  // position, velocity, acceleration

  if (!constraint->add_point_fx_constraint(0.0, 0.0)) {
    const std::string msg = "add st start point constraint failed";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!constraint->add_point_derivative_constraint(0.0, init_point_.v())) {
    const std::string msg = "add st start point velocity constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!constraint->add_point_second_derivative_constraint(0.0,
                                                          init_point_.a())) {
    const std::string msg =
        "add st start point acceleration constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  if (!constraint->add_point_second_derivative_constraint(
          spline_generator_->spline().x_knots().back(), 0.0)) {
    const std::string msg = "add st end point acceleration constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // monotone constraint
  if (!constraint->add_monotone_fx_inequality_constraint_at_knots()) {
    const std::string msg = "add monotonicity constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // smoothness constraint
  if (!constraint->add_third_derivative_smooth_constraint()) {
    const std::string msg = "add smoothness joint constraint failed!";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  // boundary constraint
  std::vector<double> s_upper_bound;
  std::vector<double> s_lower_bound;

  for (const double curr_t : t_knots_) {
    double lower_s = 0.0;
    double upper_s = 0.0;
    GetSConstraintByTime(boundaries, curr_t,
                         qp_spline_st_speed_config_.total_path_length(),
                         &upper_s, &lower_s);
    s_upper_bound.push_back(upper_s);
    s_lower_bound.push_back(lower_s);
  }
  if (!constraint->add_fx_boundary(t_knots_, s_lower_bound, s_upper_bound)) {
    const std::string msg = "Fail to apply obstacle constraint";
    AERROR << msg;
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  // TODO(Liangliang):
  // add speed constraint and other limits according to adu/planning
  return Status::OK();
}

Status QpSplineStGraph::ApplyKernel(
    const std::vector<StGraphBoundary>& boundaries,
    const SpeedLimit& speed_limit) {
  Spline1dKernel* spline_kernel = spline_generator_->mutable_spline_kernel();

  if (qp_spline_st_speed_config_.speed_kernel_weight() > 0) {
    spline_kernel->add_derivative_kernel_matrix(
        qp_spline_st_speed_config_.speed_kernel_weight());
  }

  if (qp_spline_st_speed_config_.accel_kernel_weight() > 0) {
    spline_kernel->add_second_order_derivative_matrix(
        qp_spline_st_speed_config_.accel_kernel_weight());
  }

  if (qp_spline_st_speed_config_.jerk_kernel_weight() > 0) {
    spline_kernel->add_third_order_derivative_matrix(
        qp_spline_st_speed_config_.jerk_kernel_weight());
  }

  // add reference line for follow
  for (const auto& boundary : boundaries) {
    if (boundary.boundary_type() == StGraphBoundary::BoundaryType::FOLLOW) {
      AddFollowReferenceLineKernel(boundary);
    }
  }

  // TODO(all): add reference speed profile for different main decision
  std::vector<double> s_vec;
  if (speed_limit.speed_limits().size() == 0) {
    return Status(ErrorCode::PLANNING_ERROR,
                  "Fail to apply_kernel due to empty speed limits.");
  }
  double dist_ref = 0.0;
  for (uint32_t i = 0;
       i <= qp_spline_st_speed_config_.number_of_discrete_graph_t(); ++i) {
    s_vec.push_back(dist_ref);
    dist_ref += time_resolution_ * speed_limit.get_speed_limit(dist_ref);
  }
  // TODO: change reference line kernel to configurable version
  spline_kernel->add_reference_line_kernel_matrix(t_knots_, s_vec, 1);

  return Status::OK();
}

Status QpSplineStGraph::Solve() {
  return spline_generator_->solve()
             ? Status::OK()
             : Status(ErrorCode::PLANNING_ERROR, "QpSplineStGraph::solve");
}

Status QpSplineStGraph::AddFollowReferenceLineKernel(
    const StGraphBoundary& follow_boundary) {
  if (follow_boundary.boundary_type() !=
      StGraphBoundary::BoundaryType::FOLLOW) {
    std::string msg = common::util::StrCat(
        "Fail to add follow reference line kernel because boundary type is ",
        "incorrect. type: ", static_cast<int>(follow_boundary.boundary_type()),
        ".");
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }

  auto* spline_kernel = spline_generator_->mutable_spline_kernel();
  std::vector<double> ref_s;
  for (const double curr_t : t_knots_) {
    double s_upper = 0.0;
    double s_lower = 0.0;
    if (follow_boundary.get_s_boundary_position(curr_t, &s_upper, &s_lower)) {
      ref_s.push_back(s_upper - follow_boundary.characteristic_length());
    }
    ref_s.push_back(s_upper);
  }

  spline_kernel->add_reference_line_kernel_matrix(t_knots_, ref_s, 1.0);
  return Status::OK();
}

Status QpSplineStGraph::GetSConstraintByTime(
    const std::vector<StGraphBoundary>& boundaries, const double time,
    const double total_path_s, double* const s_upper_bound,
    double* const s_lower_bound) const {
  *s_upper_bound =
      std::min(total_path_s, time * qp_spline_st_speed_config_.max_speed());

  for (const StGraphBoundary& boundary : boundaries) {
    double s_upper = 0.0;
    double s_lower = 0.0;

    if (!boundary.get_s_boundary_position(time, &s_upper, &s_lower)) {
      continue;
    }

    if (boundary.boundary_type() == StGraphBoundary::BoundaryType::STOP ||
        boundary.boundary_type() == StGraphBoundary::BoundaryType::FOLLOW ||
        boundary.boundary_type() == StGraphBoundary::BoundaryType::YIELD) {
      *s_upper_bound = std::fmin(*s_upper_bound, s_upper);
    } else {
      *s_lower_bound = std::fmax(*s_lower_bound, s_lower);
    }
  }

  return Status::OK();
}
}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before><commit_msg>Refactoring: move Runfile out of unnamed namespace<commit_after><|endoftext|>