<commit_before>#include <QMenu>
#include <QScrollBar>

#include "QGCMessageView.h"
#include "GAudioOutput.h"
#include "QGCUnconnectedInfoWidget.h"
#include "UASManager.h"
#include "ui_QGCMessageView.h"

QGCMessageView::QGCMessageView(QWidget *parent) :
    QWidget(parent),
    activeUAS(NULL),
    ui(new Ui::QGCMessageView)
{
    setObjectName("QUICKVIEW_MESSAGE_CONSOLE")  ;

    ui->setupUi(this);
    setStyleSheet("QPlainTextEdit { border: 0px }");

    // Construct initial widget
    connectWidget = new QGCUnconnectedInfoWidget(this);
    ui->horizontalLayout->addWidget(connectWidget);
    ui->plainTextEdit->hide();

    // Enable the right-click menu for the text editor. This works because the plainTextEdit
    // widget has its context menu policy set to its actions list. So we any actions we add
    // to this widget's action list will be automatically displayed.
    // We only have the clear action right now.
    QAction* clearAction = new QAction(tr("Clear Text"), this);
    connect(clearAction, SIGNAL(triggered()), ui->plainTextEdit, SLOT(clear()));
    ui->plainTextEdit->addAction(clearAction);

    // Connect to the currently active UAS.
    setActiveUAS(UASManager::instance()->getActiveUAS());
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
}

QGCMessageView::~QGCMessageView()
{
    // The only thing we need to delete is the ui because it's the only thing not cleaned up automatically
    // by the deletion of its parent.
    delete ui;
}

void QGCMessageView::setActiveUAS(UASInterface* uas)
{
    // If we were already attached to an autopilot, disconnect it, restoring
    // the widget to its initial state as needed.
    if (activeUAS)
    {
        disconnect(activeUAS, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString)));
        ui->plainTextEdit->clear();
        activeUAS = NULL;
    }

    // And now if there's an autopilot to follow, set up the UI.
    if (uas)
    {
        // Make sure the UI is configured for showing messages.
        // Note that this call is NOT equivalent to `connectWidget->isVisible()`.
        if (!connectWidget->isHidden())
        {
            connectWidget->hide();
            ui->plainTextEdit->show();
        }

        // And connect to the new UAS.
        connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString)));
        activeUAS = uas;
    }
    // But if there's no new autopilot, restore the connect button.
    else
    {
        connectWidget->show();
        ui->plainTextEdit->hide();
    }
}

void QGCMessageView::handleTextMessage(int uasid, int compId, int severity, QString text)
{
    QPlainTextEdit *msgWidget = ui->plainTextEdit;

    // Turn off updates while we're appending content to avoid breaking the autoscroll behavior
    msgWidget->setUpdatesEnabled(false);
    QScrollBar *scroller = msgWidget->verticalScrollBar();

    // Get all the UAS info.
    UASInterface *uas = UASManager::instance()->getUASForId(uasid);
    QString uasName(uas->getUASName());
    QString colorName(uas->getColor().name());

    // Color the output depending on the message severity. We have 3 distinct cases:
    // 1: If we have an ERROR or worse, make it bigger, bolder, and highlight it.
    // 2: If we have a warning or notice, just make it bold.
    // 3: Otherwise color it the standard color.

    // So first deteremine the styling based on the severity.
    QString style;
    switch (severity)
    {
    case MAV_SEVERITY_EMERGENCY:
    case MAV_SEVERITY_ALERT:
    case MAV_SEVERITY_CRITICAL:
    case MAV_SEVERITY_ERROR:
        // TODO: Move this audio output to UAS.cc, as it doesn't make sense to put audio output in a message logger widget.
        GAudioOutput::instance()->say(text.toLower());
        style = QString("color:#DC143C;font-size:large;font-weight:bold");
        break;
    case MAV_SEVERITY_WARNING:
    case MAV_SEVERITY_NOTICE:
        style = QString("color:%1;font-weight:bold").arg(colorName);
        break;
    default:
        style = QString("color:%1;").arg(colorName);
        break;
    }

    // And determine the text for the severities.
    QString severityText("");
    switch (severity)
    {
    case MAV_SEVERITY_EMERGENCY:
        severityText = QString(tr("EMERGENCY"));
        break;
    case MAV_SEVERITY_ALERT:
        severityText = QString(tr("ALERT"));
        break;
    case MAV_SEVERITY_CRITICAL:
        severityText = QString(tr("Critical"));
        break;
    case MAV_SEVERITY_ERROR:
        severityText = QString(tr("Error"));
        break;
    case MAV_SEVERITY_WARNING:
        severityText = QString(tr("Warning"));
        break;
    case MAV_SEVERITY_NOTICE:
        severityText = QString(tr("Notice"));
        break;
    case MAV_SEVERITY_INFO:
        severityText = QString(tr("Info"));
        break;
    case MAV_SEVERITY_DEBUG:
        severityText = QString(tr("Debug"));
        break;
    default:
        severityText = QString(tr("Unknown"));
        break;
    }

    // Finally append the properly-styled text.
    msgWidget->appendHtml(QString("
[%2:%3] %4 - %5
").arg(style).arg(uasName).arg(compId).arg(severityText).arg(text));
    qDebug() << msgWidget->document()->toHtml();

    // Ensure text area scrolls correctly
    scroller->setValue(scroller->maximum());
    msgWidget->setUpdatesEnabled(true);
}<commit_msg>QGCMessageView: Added timestamps.<commit_after>#include <QMenu>
#include <QScrollBar>

#include "QGCMessageView.h"
#include "GAudioOutput.h"
#include "QGCUnconnectedInfoWidget.h"
#include "UASManager.h"
#include "ui_QGCMessageView.h"

QGCMessageView::QGCMessageView(QWidget *parent) :
    QWidget(parent),
    activeUAS(NULL),
    ui(new Ui::QGCMessageView)
{
    setObjectName("QUICKVIEW_MESSAGE_CONSOLE")  ;

    ui->setupUi(this);
    setStyleSheet("QPlainTextEdit { border: 0px }");

    // Construct initial widget
    connectWidget = new QGCUnconnectedInfoWidget(this);
    ui->horizontalLayout->addWidget(connectWidget);
    ui->plainTextEdit->hide();

    // Enable the right-click menu for the text editor. This works because the plainTextEdit
    // widget has its context menu policy set to its actions list. So we any actions we add
    // to this widget's action list will be automatically displayed.
    // We only have the clear action right now.
    QAction* clearAction = new QAction(tr("Clear Text"), this);
    connect(clearAction, SIGNAL(triggered()), ui->plainTextEdit, SLOT(clear()));
    ui->plainTextEdit->addAction(clearAction);

    // Connect to the currently active UAS.
    setActiveUAS(UASManager::instance()->getActiveUAS());
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
}

QGCMessageView::~QGCMessageView()
{
    // The only thing we need to delete is the ui because it's the only thing not cleaned up automatically
    // by the deletion of its parent.
    delete ui;
}

void QGCMessageView::setActiveUAS(UASInterface* uas)
{
    // If we were already attached to an autopilot, disconnect it, restoring
    // the widget to its initial state as needed.
    if (activeUAS)
    {
        disconnect(activeUAS, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString)));
        ui->plainTextEdit->clear();
        activeUAS = NULL;
    }

    // And now if there's an autopilot to follow, set up the UI.
    if (uas)
    {
        // Make sure the UI is configured for showing messages.
        // Note that this call is NOT equivalent to `connectWidget->isVisible()`.
        if (!connectWidget->isHidden())
        {
            connectWidget->hide();
            ui->plainTextEdit->show();
        }

        // And connect to the new UAS.
        connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString)));
        activeUAS = uas;
    }
    // But if there's no new autopilot, restore the connect button.
    else
    {
        connectWidget->show();
        ui->plainTextEdit->hide();
    }
}

void QGCMessageView::handleTextMessage(int uasid, int compId, int severity, QString text)
{
    QPlainTextEdit *msgWidget = ui->plainTextEdit;

    // Turn off updates while we're appending content to avoid breaking the autoscroll behavior
    msgWidget->setUpdatesEnabled(false);
    QScrollBar *scroller = msgWidget->verticalScrollBar();

    // Get all the UAS info.
    UASInterface *uas = UASManager::instance()->getUASForId(uasid);
    QString uasName(uas->getUASName());
    QString colorName(uas->getColor().name());

    // Color the output depending on the message severity. We have 3 distinct cases:
    // 1: If we have an ERROR or worse, make it bigger, bolder, and highlight it.
    // 2: If we have a warning or notice, just make it bold.
    // 3: Otherwise color it the standard color.

    // So first deteremine the styling based on the severity.
    QString style;
    switch (severity)
    {
    case MAV_SEVERITY_EMERGENCY:
    case MAV_SEVERITY_ALERT:
    case MAV_SEVERITY_CRITICAL:
    case MAV_SEVERITY_ERROR:
        // TODO: Move this audio output to UAS.cc, as it doesn't make sense to put audio output in a message logger widget.
        GAudioOutput::instance()->say(text.toLower());
        style = QString("color:#DC143C;font-size:large;font-weight:bold");
        break;
    case MAV_SEVERITY_WARNING:
    case MAV_SEVERITY_NOTICE:
        style = QString("color:%1;font-weight:bold").arg(colorName);
        break;
    default:
        style = QString("color:%1;").arg(colorName);
        break;
    }

    // And determine the text for the severities.
    QString severityText("");
    switch (severity)
    {
    case MAV_SEVERITY_EMERGENCY:
        severityText = QString(tr("EMERGENCY"));
        break;
    case MAV_SEVERITY_ALERT:
        severityText = QString(tr("ALERT"));
        break;
    case MAV_SEVERITY_CRITICAL:
        severityText = QString(tr("Critical"));
        break;
    case MAV_SEVERITY_ERROR:
        severityText = QString(tr("Error"));
        break;
    case MAV_SEVERITY_WARNING:
        severityText = QString(tr("Warning"));
        break;
    case MAV_SEVERITY_NOTICE:
        severityText = QString(tr("Notice"));
        break;
    case MAV_SEVERITY_INFO:
        severityText = QString(tr("Info"));
        break;
    case MAV_SEVERITY_DEBUG:
        severityText = QString(tr("Debug"));
        break;
    default:
        severityText = QString(tr("Unknown"));
        break;
    }

    // Finally append the properly-styled text with a timestamp.
    QString dateString = QDateTime::currentDateTime().toString(Qt::SystemLocaleShortDate);
    msgWidget->appendHtml(QString("
[%2][%3:%4] %5 - %6
").arg(style).arg(dateString).arg(uasName).arg(compId).arg(severityText).arg(text));
    qDebug() << msgWidget->document()->toHtml();

    // Ensure text area scrolls correctly
    scroller->setValue(scroller->maximum());
    msgWidget->setUpdatesEnabled(true);
}<|endoftext|>


<commit_before>#include "util/bitmap.h"
#include "util/trans-bitmap.h"

#include "context-box.h"
#include "util/font.h"
#include <math.h>

#include "util/token.h"

static const double FONT_SPACER = 1.3;
static const int GradientMax = 50;

static Graphics::Color selectedGradientStart(){
    static Graphics::Color color = Graphics::makeColor(19, 167, 168);
    return color;
}

static Graphics::Color selectedGradientEnd(){
    static Graphics::Color color = Graphics::makeColor(27, 237, 239);
    return color;
}

using namespace std;

namespace Gui{

Effects::Gradient standardGradient(int max){
    Effects::Gradient standard(max, selectedGradientStart(), selectedGradientEnd());
    return standard;
}

Effects::Gradient modifiedGradient(Graphics::Color low, Graphics::Color high, int max){
    Effects::Gradient modified(max, low, high);
    return modified;
}

ListValues::ListValues():
interpolate(true),
lowColor(selectedGradientStart()),
highColor(selectedGradientEnd()),
maxGradient(GradientMax),
selectedColor(selectedGradientStart()),
selectedAlpha(255),
otherColor(Graphics::makeColor(255, 255, 255)),
otherAlpha(255),
fade(true){
}

ListValues::ListValues(const ListValues & copy):
interpolate(copy.interpolate),
lowColor(copy.lowColor),
highColor(copy.highColor),
maxGradient(copy.maxGradient),
selectedColor(copy.selectedColor),
selectedAlpha(copy.selectedAlpha),
otherColor(copy.otherColor),
otherAlpha(copy.otherAlpha),
fade(copy.fade){
}

ListValues::~ListValues(){
}

const ListValues & ListValues::operator=(const ListValues & copy){
    interpolate = copy.interpolate;
    lowColor = copy.lowColor;
    highColor = copy.highColor;
    maxGradient = copy.maxGradient;
    selectedColor = copy.selectedColor;
    selectedAlpha = copy.selectedAlpha;
    otherColor = copy.otherColor;
    otherAlpha = copy.otherAlpha;
    fade = copy.fade;

    return *this;
}

static int clamp(int in, int low = 0, int high = 255){
    if (in < low){
        return low;
    }
    if (in > high){
        return high;
    }
    return in;
}

void ListValues::getValues(const Token * token){
    TokenView view = token->view();
    while (view.hasMore()){
        const Token * token;
        view >> token;
        try{
            int red = 0, green = 0, blue = 0, alpha = 0, gradient=1;
            if (token->match("interpolate-selected", interpolate)){
            } else if (token->match("color-low", red, green, blue)){
                lowColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("color-high", red, green, blue)){
                highColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("interpolate-distance", gradient)){
                maxGradient = clamp(gradient, 1, 1000);
            } else if (token->match("selected-color", red, green, blue)){
                selectedColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("selected-color-alpha", alpha)){
                selectedAlpha = clamp(alpha);
            } else if (token->match("other-color", red, green, blue)){
                otherColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("other-color-alpha", alpha)){
                otherAlpha = clamp(alpha);
            } else if (token->match("distance-fade", fade)){
            }
        } catch (const TokenException & ex){
            // Output something
        }
    }
}

ContextItem::ContextItem(const std::string & name, const ContextBox & parent):
text(name),
parent(parent){
}

ContextItem::~ContextItem(){
}

void ContextItem::draw(int x, int y, const Graphics::Bitmap & where, const Font & font, int distance) const {
    if (distance == 0){
        if (parent.getListValues().getInterpolate()){
            Graphics::Bitmap::transBlender(0, 0, 0, parent.getFadeAlpha());
            font.printf(x, y, parent.getSelectedColor(), where.translucent(), getText(), 0);
        } else {
            Graphics::Bitmap::transBlender(0, 0, 0, parent.getListValues().getSelectedAlpha());
            font.printf(x, y, parent.getListValues().getSelectedColor(), where.translucent(), getText(), 0);
        }
    } else {
        if (parent.getListValues().getDistanceFade()){
            int alpha = parent.getFadeAlpha() - fabs((double) distance) * 35;
            if (alpha < 0){
                alpha = 0;
            }
            Graphics::Bitmap::transBlender(0, 0, 0, alpha);
            font.printf(x, y, parent.getListValues().getOtherColor(), where.translucent(), getText(), 0);
        } else {
            Graphics::Bitmap::transBlender(0, 0, 0, parent.getListValues().getOtherAlpha());
            font.printf(x, y, parent.getListValues().getOtherColor(), where.translucent(), getText(), 0);
        }
    }
}

void ContextItem::setText(const LanguageString & t){
    text = t;
}

int ContextItem::size(const Font & font) const {
    return font.textLength(getText().c_str());
}

ContextBox::ContextBox():
fadeState(NotActive),
list(new ScrollList()),
fadeSpeed(12),
fadeAlpha(0),
cursorCenter(0),
cursorLocation(0),
scrollWait(4),
selectedGradient(standardGradient(GradientMax)),
renderOnlyText(false){
}
ContextBox::ContextBox( const ContextBox & copy ):
fadeState(NotActive),
list(new ScrollList()),
selectedGradient(standardGradient(GradientMax)),
renderOnlyText(false){
    this->list = copy.list;
    this->fadeSpeed = copy.fadeSpeed;
    this->fadeAlpha = copy.fadeAlpha;
    this->cursorCenter = copy.cursorCenter;
    this->cursorLocation = copy.cursorLocation;
    this->scrollWait = copy.scrollWait;
    this->renderOnlyText = copy.renderOnlyText;
}
ContextBox::~ContextBox(){
}
ContextBox & ContextBox::operator=( const ContextBox & copy){
    this->fadeState = NotActive;
    this->list = copy.list;
    this->fadeSpeed = copy.fadeSpeed;
    this->fadeAlpha = copy.fadeAlpha;
    this->cursorCenter = copy.cursorCenter;
    this->cursorLocation = copy.cursorLocation;
    this->scrollWait = copy.scrollWait;
    this->renderOnlyText = copy.renderOnlyText;
    return *this;
}

void ContextBox::act(const Font & font){
    // update board
    board.act(font);

    // Calculate text info
    list->act();

    // do fade
    doFade();

    // Update gradient
    selectedGradient.update();
}

void ContextBox::render(const Graphics::Bitmap & work){
}

void ContextBox::render(const Graphics::Bitmap & work, const Font & font){
    if (!renderOnlyText){
	board.render(work);
    }
    drawText(work, font);
}

bool ContextBox::next(const Font & font){
    if (fadeState == FadeOut){
        return false;
    }

    list->next();

    return true;
}

bool ContextBox::previous(const Font & font){
    if (fadeState == FadeOut){
        return false;
    }

    list->previous();

    return true;
}

Graphics::Color ContextBox::getSelectedColor() const {
    return values.getInterpolate() ? selectedGradient.current() : values.getSelectedColor();
}

void ContextBox::setListValues(const Gui::ListValues & values){
    this->values = values;
    selectedGradient = modifiedGradient(values.getLowColor(), values.getHighColor(), values.getMaxGradient());
}

void ContextBox::adjustLeft(){
}

void ContextBox::adjustRight(){
}

void ContextBox::open(){
    // Set the fade stuff
    fadeState = FadeIn;
    //board.position = position;
    board.location = location;
    board.transforms = transforms;
    board.colors = colors;
    board.open();
    fadeAlpha = 0;
    cursorLocation = 0;
}

void ContextBox::close(){
    fadeState = FadeOut;
    board.close();
    fadeAlpha = 255;
    cursorLocation = 480;
}

void ContextBox::doFade(){
    switch (fadeState){
        case FadeIn: {
            if (fadeAlpha < 255){
                fadeAlpha += (fadeSpeed+2);
            }

            if (fadeAlpha >= 255){
                fadeAlpha = 255;
                if (board.isActive()){
                    fadeState = Active;
                }
            }
            break;
        }
        case FadeOut: {
            if (fadeAlpha > 0){
                fadeAlpha -= (fadeSpeed+2);
            }

            if (fadeAlpha <= 0){
                fadeAlpha = 0;
                if (!board.isActive()){
                    fadeState = NotActive;
                }
            }
            break;
        }
        case Active:
        case NotActive:
        default:
            break;
    }
}

void ContextBox::setList(const std::vector<Util::ReferenceCount<ContextItem> > & list){
    this->list->clearItems();
    for (vector<Util::ReferenceCount<ContextItem> >::const_iterator it = list.begin(); it != list.end(); it++){
        const Util::ReferenceCount<ContextItem> & item = *it;
        this->list->addItem(item.convert<ScrollItem>());
    }
}

void ContextBox::addItem(const Util::ReferenceCount<ContextItem> & item){
    this->list->addItem(item.convert<ScrollItem>());
}

void ContextBox::setListType(const ListType & type){
    switch (type){
        case Normal:{
            Util::ReferenceCount<ScrollListInterface> newList = new NormalList();
            newList->addItems(list->getItems());
            list = newList;
            break;
        }
        case Scroll:{
            Util::ReferenceCount<ScrollListInterface> newList = new ScrollList();
            newList->addItems(list->getItems());
            list = newList;
            break;
        }
        default:
            break;
    }
}

void ContextBox::setListWrap(bool wrap){
    list->setWrap(wrap);
}

void ContextBox::drawText(const Graphics::Bitmap & bmp, const Font & font){
    const int x1 = board.getArea().getX()+(int)(board.getTransforms().getRadius()/2);
    const int y1 = board.getArea().getY()+2;//(board.getArea().radius/2);
    const int x2 = board.getArea().getX2()-(int)(board.getTransforms().getRadius()/2);
    const int y2 = board.getArea().getY2()-2;//(board.getArea().radius/2);

    Graphics::Bitmap area(bmp, x1, y1, x2 - x1, y2 - y1);

    list->render(area, font);
}

}
<commit_msg>Utilize otherAlpha when computing distance<commit_after>#include "util/bitmap.h"
#include "util/trans-bitmap.h"

#include "context-box.h"
#include "util/font.h"
#include <math.h>

#include "util/token.h"

static const double FONT_SPACER = 1.3;
static const int GradientMax = 50;

static Graphics::Color selectedGradientStart(){
    static Graphics::Color color = Graphics::makeColor(19, 167, 168);
    return color;
}

static Graphics::Color selectedGradientEnd(){
    static Graphics::Color color = Graphics::makeColor(27, 237, 239);
    return color;
}

using namespace std;

namespace Gui{

Effects::Gradient standardGradient(int max){
    Effects::Gradient standard(max, selectedGradientStart(), selectedGradientEnd());
    return standard;
}

Effects::Gradient modifiedGradient(Graphics::Color low, Graphics::Color high, int max){
    Effects::Gradient modified(max, low, high);
    return modified;
}

ListValues::ListValues():
interpolate(true),
lowColor(selectedGradientStart()),
highColor(selectedGradientEnd()),
maxGradient(GradientMax),
selectedColor(selectedGradientStart()),
selectedAlpha(255),
otherColor(Graphics::makeColor(255, 255, 255)),
otherAlpha(255),
fade(true){
}

ListValues::ListValues(const ListValues & copy):
interpolate(copy.interpolate),
lowColor(copy.lowColor),
highColor(copy.highColor),
maxGradient(copy.maxGradient),
selectedColor(copy.selectedColor),
selectedAlpha(copy.selectedAlpha),
otherColor(copy.otherColor),
otherAlpha(copy.otherAlpha),
fade(copy.fade){
}

ListValues::~ListValues(){
}

const ListValues & ListValues::operator=(const ListValues & copy){
    interpolate = copy.interpolate;
    lowColor = copy.lowColor;
    highColor = copy.highColor;
    maxGradient = copy.maxGradient;
    selectedColor = copy.selectedColor;
    selectedAlpha = copy.selectedAlpha;
    otherColor = copy.otherColor;
    otherAlpha = copy.otherAlpha;
    fade = copy.fade;

    return *this;
}

static int clamp(int in, int low = 0, int high = 255){
    if (in < low){
        return low;
    }
    if (in > high){
        return high;
    }
    return in;
}

void ListValues::getValues(const Token * token){
    TokenView view = token->view();
    while (view.hasMore()){
        const Token * token;
        view >> token;
        try{
            int red = 0, green = 0, blue = 0, alpha = 0, gradient=1;
            if (token->match("interpolate-selected", interpolate)){
            } else if (token->match("color-low", red, green, blue)){
                lowColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("color-high", red, green, blue)){
                highColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("interpolate-distance", gradient)){
                maxGradient = clamp(gradient, 1, 1000);
            } else if (token->match("selected-color", red, green, blue)){
                selectedColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("selected-color-alpha", alpha)){
                selectedAlpha = clamp(alpha);
            } else if (token->match("other-color", red, green, blue)){
                otherColor = Graphics::makeColor(clamp(red), clamp(green), clamp(blue));
            } else if (token->match("other-color-alpha", alpha)){
                otherAlpha = clamp(alpha);
            } else if (token->match("distance-fade", fade)){
            }
        } catch (const TokenException & ex){
            // Output something
        }
    }
}

ContextItem::ContextItem(const std::string & name, const ContextBox & parent):
text(name),
parent(parent){
}

ContextItem::~ContextItem(){
}

void ContextItem::draw(int x, int y, const Graphics::Bitmap & where, const Font & font, int distance) const {
    if (distance == 0){
        if (parent.getListValues().getInterpolate()){
            Graphics::Bitmap::transBlender(0, 0, 0, parent.getFadeAlpha());
            font.printf(x, y, parent.getSelectedColor(), where.translucent(), getText(), 0);
        } else {
            Graphics::Bitmap::transBlender(0, 0, 0, parent.getListValues().getSelectedAlpha());
            font.printf(x, y, parent.getListValues().getSelectedColor(), where.translucent(), getText(), 0);
        }
    } else {
        if (parent.getListValues().getDistanceFade()){
            int alpha = parent.getListValues().getOtherAlpha() - fabs((double) distance) * 35;
            if (alpha < 0){
                alpha = 0;
            }
            Graphics::Bitmap::transBlender(0, 0, 0, alpha);
            font.printf(x, y, parent.getListValues().getOtherColor(), where.translucent(), getText(), 0);
        } else {
            Graphics::Bitmap::transBlender(0, 0, 0, parent.getListValues().getOtherAlpha());
            font.printf(x, y, parent.getListValues().getOtherColor(), where.translucent(), getText(), 0);
        }
    }
}

void ContextItem::setText(const LanguageString & t){
    text = t;
}

int ContextItem::size(const Font & font) const {
    return font.textLength(getText().c_str());
}

ContextBox::ContextBox():
fadeState(NotActive),
list(new ScrollList()),
fadeSpeed(12),
fadeAlpha(0),
cursorCenter(0),
cursorLocation(0),
scrollWait(4),
selectedGradient(standardGradient(GradientMax)),
renderOnlyText(false){
}
ContextBox::ContextBox( const ContextBox & copy ):
fadeState(NotActive),
list(new ScrollList()),
selectedGradient(standardGradient(GradientMax)),
renderOnlyText(false){
    this->list = copy.list;
    this->fadeSpeed = copy.fadeSpeed;
    this->fadeAlpha = copy.fadeAlpha;
    this->cursorCenter = copy.cursorCenter;
    this->cursorLocation = copy.cursorLocation;
    this->scrollWait = copy.scrollWait;
    this->renderOnlyText = copy.renderOnlyText;
}
ContextBox::~ContextBox(){
}
ContextBox & ContextBox::operator=( const ContextBox & copy){
    this->fadeState = NotActive;
    this->list = copy.list;
    this->fadeSpeed = copy.fadeSpeed;
    this->fadeAlpha = copy.fadeAlpha;
    this->cursorCenter = copy.cursorCenter;
    this->cursorLocation = copy.cursorLocation;
    this->scrollWait = copy.scrollWait;
    this->renderOnlyText = copy.renderOnlyText;
    return *this;
}

void ContextBox::act(const Font & font){
    // update board
    board.act(font);

    // Calculate text info
    list->act();

    // do fade
    doFade();

    // Update gradient
    selectedGradient.update();
}

void ContextBox::render(const Graphics::Bitmap & work){
}

void ContextBox::render(const Graphics::Bitmap & work, const Font & font){
    if (!renderOnlyText){
	board.render(work);
    }
    drawText(work, font);
}

bool ContextBox::next(const Font & font){
    if (fadeState == FadeOut){
        return false;
    }

    list->next();

    return true;
}

bool ContextBox::previous(const Font & font){
    if (fadeState == FadeOut){
        return false;
    }

    list->previous();

    return true;
}

Graphics::Color ContextBox::getSelectedColor() const {
    return values.getInterpolate() ? selectedGradient.current() : values.getSelectedColor();
}

void ContextBox::setListValues(const Gui::ListValues & values){
    this->values = values;
    selectedGradient = modifiedGradient(values.getLowColor(), values.getHighColor(), values.getMaxGradient());
}

void ContextBox::adjustLeft(){
}

void ContextBox::adjustRight(){
}

void ContextBox::open(){
    // Set the fade stuff
    fadeState = FadeIn;
    //board.position = position;
    board.location = location;
    board.transforms = transforms;
    board.colors = colors;
    board.open();
    fadeAlpha = 0;
    cursorLocation = 0;
}

void ContextBox::close(){
    fadeState = FadeOut;
    board.close();
    fadeAlpha = 255;
    cursorLocation = 480;
}

void ContextBox::doFade(){
    switch (fadeState){
        case FadeIn: {
            if (fadeAlpha < 255){
                fadeAlpha += (fadeSpeed+2);
            }

            if (fadeAlpha >= 255){
                fadeAlpha = 255;
                if (board.isActive()){
                    fadeState = Active;
                }
            }
            break;
        }
        case FadeOut: {
            if (fadeAlpha > 0){
                fadeAlpha -= (fadeSpeed+2);
            }

            if (fadeAlpha <= 0){
                fadeAlpha = 0;
                if (!board.isActive()){
                    fadeState = NotActive;
                }
            }
            break;
        }
        case Active:
        case NotActive:
        default:
            break;
    }
}

void ContextBox::setList(const std::vector<Util::ReferenceCount<ContextItem> > & list){
    this->list->clearItems();
    for (vector<Util::ReferenceCount<ContextItem> >::const_iterator it = list.begin(); it != list.end(); it++){
        const Util::ReferenceCount<ContextItem> & item = *it;
        this->list->addItem(item.convert<ScrollItem>());
    }
}

void ContextBox::addItem(const Util::ReferenceCount<ContextItem> & item){
    this->list->addItem(item.convert<ScrollItem>());
}

void ContextBox::setListType(const ListType & type){
    switch (type){
        case Normal:{
            Util::ReferenceCount<ScrollListInterface> newList = new NormalList();
            newList->addItems(list->getItems());
            list = newList;
            break;
        }
        case Scroll:{
            Util::ReferenceCount<ScrollListInterface> newList = new ScrollList();
            newList->addItems(list->getItems());
            list = newList;
            break;
        }
        default:
            break;
    }
}

void ContextBox::setListWrap(bool wrap){
    list->setWrap(wrap);
}

void ContextBox::drawText(const Graphics::Bitmap & bmp, const Font & font){
    const int x1 = board.getArea().getX()+(int)(board.getTransforms().getRadius()/2);
    const int y1 = board.getArea().getY()+2;//(board.getArea().radius/2);
    const int x2 = board.getArea().getX2()-(int)(board.getTransforms().getRadius()/2);
    const int y2 = board.getArea().getY2()-2;//(board.getArea().radius/2);

    Graphics::Bitmap area(bmp, x1, y1, x2 - x1, y2 - y1);

    list->render(area, font);
}

}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <gtest/gtest.h>
#include <arrayfire.h>
#include <af/data.h>
#include <af/dim4.hpp>
#include <af/traits.hpp>
#include <vector>
#include <iostream>
#include <string>
#include <testHelpers.hpp>

using std::vector;
using std::string;
using std::cout;
using std::endl;
using af::cfloat;
using af::cdouble;

template<typename T>
class Random : public ::testing::Test
{
    public:
        virtual void SetUp() {
        }
};

// create a list of types to be tested
typedef ::testing::Types<float, cfloat, double, cdouble, int, unsigned, unsigned char> TestTypes;

// register the type list
TYPED_TEST_CASE(Random, TestTypes);

template<typename T>
class Random_norm : public ::testing::Test
{
    public:
        virtual void SetUp() {
        }
};

// create a list of types to be tested
typedef ::testing::Types<float, cfloat, double, cdouble> TestTypesNorm;

// register the type list
TYPED_TEST_CASE(Random_norm, TestTypesNorm);

template<typename T>
void randuTest(af::dim4 & dims)
{
    if (noDoubleTests<T>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_SUCCESS, af_randu(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<T>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<typename T>
void randnTest(af::dim4 &dims)
{
    if (noDoubleTests<T>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_SUCCESS, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<T>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

// INT, UNIT, CHAR, UCHAR Not Supported by RANDN
template<>
void randnTest<int>(af::dim4 &dims)
{
    if (noDoubleTests<int>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<int>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<>
void randnTest<unsigned>(af::dim4 &dims)
{
    if (noDoubleTests<unsigned>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<unsigned>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<>
void randnTest<char>(af::dim4 &dims)
{
    if (noDoubleTests<char>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<char>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<>
void randnTest<unsigned char>(af::dim4 &dims)
{
    if (noDoubleTests<unsigned char>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<unsigned char>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

#define RAND(d0, d1, d2, d3)                            \
    TYPED_TEST(Random,randu_##d0##_##d1##_##d2##_##d3)                \
    {                                                   \
        af::dim4 dims(d0, d1, d2, d3);                  \
        randuTest<TypeParam>(dims);                     \
    }                                                   \
    TYPED_TEST(Random,randn_##d0##_##d1##_##d2##_##d3)                \
    {                                                   \
        af::dim4 dims(d0, d1, d2, d3);                  \
        randnTest<TypeParam>(dims);                     \
    }                                                   \

RAND(1024, 1024,    1,    1);
RAND( 512,  512,    1,    1);
RAND( 256,  256,    1,    1);
RAND( 128,  128,    1,    1);
RAND(  64,   64,    1,    1);
RAND(  32,   32,    1,    1);
RAND(  16,   16,    1,    1);
RAND(   8,    8,    1,    1);
RAND(   4,    4,    1,    1);
RAND(   2,    2,    2,    2);
RAND(   1,    1,    1,    1);
RAND( 256,   16,    4,    2);
RAND(  32,   16,    8,    4);
RAND(   2,    4,   16,  256);
RAND(   4,    8,   16,   32);

RAND(  10,   10,   10,   10);

RAND(1920, 1080,    1,    1);
RAND(1280,  720,    1,    1);
RAND( 640,  480,    1,    1);

RAND( 215,   24,    6,    5);
RAND( 132,   64,   23,    2);
RAND(  15,   35,   50,    3);
RAND(  77,   43,    8,    1);
RAND( 123,   45,    6,    7);
RAND( 345,   28,    9,    1);
RAND(  79,   68,   12,    6);
RAND(  45,    1,    1,    1);

template<typename T>
void randuArgsTest()
{
    if (noDoubleTests<T>()) return;

    dim_type ndims = 4;
    dim_type dims[] = {1, 2, 3, 0};
    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_SIZE, af_randu(&outArray, ndims, dims, (af_dtype) af::dtype_traits<char>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

TYPED_TEST(Random,InvalidArgs)
{
    randuArgsTest<TypeParam>();
}

////////////////////////////////////// CPP /////////////////////////////////////
//
TEST(Random, CPP)
{
    if (noDoubleTests<float>()) return;

    // TEST will fail if exception is thrown, which are thrown
    // when only wrong inputs are thrown on bad access happens
    af::dim4 dims(1, 2, 3, 1);
    af::array out1 = af::randu(dims);
    af::array out2 = af::randn(dims);
}

template<typename T>
void testSetSeed(const int seed0, const int seed1, bool is_norm = false)
{

    if (noDoubleTests<T>()) return;

    const int num = 1024 * 1024;
    af::dtype ty = (af::dtype)af::dtype_traits<T>::af_type;

    af::setSeed(seed0);
    af::array in0 = is_norm ? af::randn(num, ty) : af::randu(num, ty);

    af::setSeed(seed1);
    af::array in1 = is_norm ? af::randn(num, ty) : af::randu(num, ty);

    af::setSeed(seed0);
    af::array in2 = is_norm ? af::randn(num, ty) : af::randu(num, ty);

    std::vector<T> h_in0(num);
    std::vector<T> h_in1(num);
    std::vector<T> h_in2(num);

    in0.host((void *)&h_in0[0]);
    in1.host((void *)&h_in1[0]);
    in2.host((void *)&h_in2[0]);

    for (int i = 0; i < num; i++) {
        ASSERT_EQ(h_in0[i], h_in2[i]);
    }
}

TYPED_TEST(Random, setSeed)
{
    testSetSeed<TypeParam>(10101, 23232, false);
}

TYPED_TEST(Random_norm, setSeed)
{
    testSetSeed<TypeParam>(456, 789, false);
}

template<typename T>
void testGetSeed(const int seed0, const int seed1)
{
    const int num = 1024;
    af::dtype ty = (af::dtype)af::dtype_traits<T>::af_type;

    af::setSeed(seed0);
    af::array in0 = af::randu(num, ty);
    ASSERT_EQ(af::getSeed(), seed0);

    af::setSeed(seed1);
    af::array in1 = af::randu(num, ty);
    ASSERT_EQ(af::getSeed(), seed1);

    af::setSeed(seed0);
    af::array in2 = af::randu(num, ty);
    ASSERT_EQ(af::getSeed(), seed0);
}

TYPED_TEST(Random, getSeed)
{
    testGetSeed<TypeParam>(1234, 9876);
}
<commit_msg>TEST: Updating random test to make sure there are no clashes<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <gtest/gtest.h>
#include <arrayfire.h>
#include <af/data.h>
#include <af/dim4.hpp>
#include <af/traits.hpp>
#include <vector>
#include <iostream>
#include <string>
#include <testHelpers.hpp>

using std::vector;
using std::string;
using std::cout;
using std::endl;
using af::cfloat;
using af::cdouble;

template<typename T>
class Random : public ::testing::Test
{
    public:
        virtual void SetUp() {
        }
};

// create a list of types to be tested
typedef ::testing::Types<float, cfloat, double, cdouble, int, unsigned, unsigned char> TestTypes;

// register the type list
TYPED_TEST_CASE(Random, TestTypes);

template<typename T>
class Random_norm : public ::testing::Test
{
    public:
        virtual void SetUp() {
        }
};

// create a list of types to be tested
typedef ::testing::Types<float, cfloat, double, cdouble> TestTypesNorm;

// register the type list
TYPED_TEST_CASE(Random_norm, TestTypesNorm);

template<typename T>
void randuTest(af::dim4 & dims)
{
    if (noDoubleTests<T>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_SUCCESS, af_randu(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<T>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<typename T>
void randnTest(af::dim4 &dims)
{
    if (noDoubleTests<T>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_SUCCESS, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<T>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

// INT, UNIT, CHAR, UCHAR Not Supported by RANDN
template<>
void randnTest<int>(af::dim4 &dims)
{
    if (noDoubleTests<int>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<int>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<>
void randnTest<unsigned>(af::dim4 &dims)
{
    if (noDoubleTests<unsigned>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<unsigned>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<>
void randnTest<char>(af::dim4 &dims)
{
    if (noDoubleTests<char>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<char>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

template<>
void randnTest<unsigned char>(af::dim4 &dims)
{
    if (noDoubleTests<unsigned char>()) return;

    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_INVALID_TYPE, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<unsigned char>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

#define RAND(d0, d1, d2, d3)                            \
    TYPED_TEST(Random,randu_##d0##_##d1##_##d2##_##d3)                \
    {                                                   \
        af::dim4 dims(d0, d1, d2, d3);                  \
        randuTest<TypeParam>(dims);                     \
    }                                                   \
    TYPED_TEST(Random,randn_##d0##_##d1##_##d2##_##d3)                \
    {                                                   \
        af::dim4 dims(d0, d1, d2, d3);                  \
        randnTest<TypeParam>(dims);                     \
    }                                                   \

RAND(1024, 1024,    1,    1);
RAND( 512,  512,    1,    1);
RAND( 256,  256,    1,    1);
RAND( 128,  128,    1,    1);
RAND(  64,   64,    1,    1);
RAND(  32,   32,    1,    1);
RAND(  16,   16,    1,    1);
RAND(   8,    8,    1,    1);
RAND(   4,    4,    1,    1);
RAND(   2,    2,    2,    2);
RAND(   1,    1,    1,    1);
RAND( 256,   16,    4,    2);
RAND(  32,   16,    8,    4);
RAND(   2,    4,   16,  256);
RAND(   4,    8,   16,   32);

RAND(  10,   10,   10,   10);

RAND(1920, 1080,    1,    1);
RAND(1280,  720,    1,    1);
RAND( 640,  480,    1,    1);

RAND( 215,   24,    6,    5);
RAND( 132,   64,   23,    2);
RAND(  15,   35,   50,    3);
RAND(  77,   43,    8,    1);
RAND( 123,   45,    6,    7);
RAND( 345,   28,    9,    1);
RAND(  79,   68,   12,    6);
RAND(  45,    1,    1,    1);

template<typename T>
void randuArgsTest()
{
    if (noDoubleTests<T>()) return;

    dim_type ndims = 4;
    dim_type dims[] = {1, 2, 3, 0};
    af_array outArray = 0;
    ASSERT_EQ(AF_ERR_SIZE, af_randu(&outArray, ndims, dims, (af_dtype) af::dtype_traits<char>::af_type));
    if(outArray != 0) af_destroy_array(outArray);
}

TYPED_TEST(Random,InvalidArgs)
{
    randuArgsTest<TypeParam>();
}

////////////////////////////////////// CPP /////////////////////////////////////
//
TEST(Random, CPP)
{
    if (noDoubleTests<float>()) return;

    // TEST will fail if exception is thrown, which are thrown
    // when only wrong inputs are thrown on bad access happens
    af::dim4 dims(1, 2, 3, 1);
    af::array out1 = af::randu(dims);
    af::array out2 = af::randn(dims);
}

template<typename T>
void testSetSeed(const int seed0, const int seed1, bool is_norm = false)
{

    if (noDoubleTests<T>()) return;

    const int num = 1024 * 1024;
    af::dtype ty = (af::dtype)af::dtype_traits<T>::af_type;

    af::setSeed(seed0);
    af::array in0 = is_norm ? af::randn(num, ty) : af::randu(num, ty);

    af::setSeed(seed1);
    af::array in1 = is_norm ? af::randn(num, ty) : af::randu(num, ty);

    af::setSeed(seed0);
    af::array in2 = is_norm ? af::randn(num, ty) : af::randu(num, ty);

    std::vector<T> h_in0(num);
    std::vector<T> h_in1(num);
    std::vector<T> h_in2(num);

    in0.host((void *)&h_in0[0]);
    in1.host((void *)&h_in1[0]);
    in2.host((void *)&h_in2[0]);

    for (int i = 0; i < num; i++) {
        // Verify if same seed produces same arrays
        ASSERT_EQ(h_in0[i], h_in2[i]);

        // Verify different arrays don't clash at same location
        // b8 and u9 can clash because they generate a small set of values
        if (ty != b8 && ty != u8) ASSERT_NE(h_in0[i], h_in1[i]);
    }
}

TYPED_TEST(Random, setSeed)
{
    testSetSeed<TypeParam>(10101, 23232, false);
}

TYPED_TEST(Random_norm, setSeed)
{
    testSetSeed<TypeParam>(456, 789, false);
}

template<typename T>
void testGetSeed(const int seed0, const int seed1)
{
    const int num = 1024;
    af::dtype ty = (af::dtype)af::dtype_traits<T>::af_type;

    af::setSeed(seed0);
    af::array in0 = af::randu(num, ty);
    ASSERT_EQ(af::getSeed(), seed0);

    af::setSeed(seed1);
    af::array in1 = af::randu(num, ty);
    ASSERT_EQ(af::getSeed(), seed1);

    af::setSeed(seed0);
    af::array in2 = af::randu(num, ty);
    ASSERT_EQ(af::getSeed(), seed0);
}

TYPED_TEST(Random, getSeed)
{
    testGetSeed<TypeParam>(1234, 9876);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 - 2017, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/timer/Timer.h>

#include <stingraykit/diagnostics/ExecutorsProfiler.h>
#include <stingraykit/function/CancellableFunction.h>
#include <stingraykit/function/bind.h>
#include <stingraykit/function/function_name_getter.h>
#include <stingraykit/log/Logger.h>
#include <stingraykit/time/ElapsedTime.h>
#include <stingraykit/FunctionToken.h>
#include <stingraykit/TaskLifeToken.h>

#include <list>
#include <map>

namespace stingray
{

	class Timer::CallbackQueue
	{
		typedef std::list<CallbackInfoPtr>					ContainerInternal;
		typedef std::map<TimeDuration, ContainerInternal>	Container;

	private:
		Mutex			_mutex;
		Container		_container;

	public:
		typedef ContainerInternal::iterator iterator;

		inline Mutex& Sync()
		{ return _mutex; }

		inline bool IsEmpty() const
		{
			MutexLock l(_mutex);
			return _container.empty();
		}

		CallbackInfoPtr Top() const;
		void Push(const CallbackInfoPtr& ci);
		void Erase(const CallbackInfoPtr& ci);
		CallbackInfoPtr Pop();
	};

	class Timer::CallbackInfo
	{
		STINGRAYKIT_NONCOPYABLE(CallbackInfo);

		typedef function<void()>			FuncT;
		typedef CallbackQueue::iterator		QueueIterator;

	private:
		FuncT						_func;
		TimeDuration				_timeToTrigger;
		optional<TimeDuration>		_period;
		TaskLifeToken				_token;

		bool						_erased;
		optional<QueueIterator>		_iterator;

	private:
		friend class CallbackQueue;

		void SetIterator(const optional<QueueIterator>& it)		{ _iterator = it; }
		const optional<QueueIterator>& GetIterator() const		{ return _iterator; }
		void SetErased()										{ _erased = true; }
		bool IsErased() const									{ return _erased; }

	public:
		CallbackInfo(const FuncT& func, const TimeDuration& timeToTrigger, const optional<TimeDuration>& period, const TaskLifeToken& token)
			:	_func(func),
				_timeToTrigger(timeToTrigger),
				_period(period),
				_token(token),
				_erased(false)
		{ }

		const FuncT& GetFunc() const							{ return _func; }
		FutureExecutionTester GetExecutionTester() const 		{ return _token.GetExecutionTester(); }
		void Release()											{ _token.Release(); }

		bool IsPeriodic() const									{ return _period; }
		void Restart(const TimeDuration& currentTime)
		{
			STINGRAYKIT_CHECK(_period, "CallbackInfo::Restart internal error: _period is set!");
			_timeToTrigger = currentTime + *_period;
		}
		TimeDuration GetTimeToTrigger() const					{ return _timeToTrigger; }
	};

	Timer::CallbackInfoPtr Timer::CallbackQueue::Top() const
	{
		MutexLock l(_mutex);
		if (!_container.empty())
		{
			const ContainerInternal& listForTop = _container.begin()->second;
			STINGRAYKIT_CHECK(!listForTop.empty(), "try to get callback from empty list");
			return listForTop.front();
		}
		else
			return null;
	}

	void Timer::CallbackQueue::Push(const CallbackInfoPtr& ci)
	{
		MutexLock l(_mutex);
		if (ci->IsErased())
			return;

		ContainerInternal& listToInsert = _container[ci->GetTimeToTrigger()];
		ci->SetIterator(listToInsert.insert(listToInsert.end(), ci));
	}

	void Timer::CallbackQueue::Erase(const CallbackInfoPtr& ci)
	{
		MutexLock l(_mutex);
		ci->SetErased();

		const optional<iterator>& it = ci->GetIterator();
		if (!it)
			return;

		TimeDuration keyToErase = ci->GetTimeToTrigger();
		ContainerInternal& listToErase = _container[keyToErase];
		listToErase.erase(*it);
		if (listToErase.empty())
			_container.erase(keyToErase);
		ci->SetIterator(null);
	}

	Timer::CallbackInfoPtr Timer::CallbackQueue::Pop()
	{
		MutexLock l(_mutex);
		STINGRAYKIT_CHECK(!_container.empty(), "popping callback from empty map");
		ContainerInternal& listToPop = _container.begin()->second;
		STINGRAYKIT_CHECK(!listToPop.empty(), "popping callback from empty list");

		CallbackInfoPtr ci = listToPop.front();
		listToPop.pop_front();
		if (listToPop.empty())
			_container.erase(ci->GetTimeToTrigger());
		ci->SetIterator(null);
		return ci;
	}

	STINGRAYKIT_DEFINE_NAMED_LOGGER(Timer);

	const TimeDuration Timer::DefaultProfileTimeout = TimeDuration::FromSeconds(10);

	Timer::Timer(const std::string& timerName, const optional<TimeDuration>& profileTimeout, const ExceptionHandler& exceptionHandler)
		:	_timerName(timerName),
			_profileTimeout(profileTimeout),
			_exceptionHandler(exceptionHandler),
			_queue(make_shared<CallbackQueue>()),
			_worker(make_shared<Thread>(timerName, bind(&Timer::ThreadFunc, this, _1)))
	{ }

	Timer::~Timer()
	{
		_worker.reset();

		MutexLock l(_queue->Sync());
		if (!_queue->IsEmpty())
			s_logger.Warning() << "killing timer " << _timerName << " which still has some functions to execute";

		while(!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Pop();
			MutexUnlock ul(l);
			top.reset();
		}
	}

	Token Timer::SetTimeout(const TimeDuration& timeout, const function<void()>& func)
	{
		const CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, null, TaskLifeToken());
		const Token token = MakeToken<FunctionToken>(bind(&Timer::RemoveTask, _queue, ci));

		{
			MutexLock l(_queue->Sync());
			_queue->Push(ci);
			_cond.Broadcast();
		}

		return token;
	}

	Token Timer::SetTimer(const TimeDuration& interval, const function<void()>& func)
	{ return SetTimer(interval, interval, func); }

	Token Timer::SetTimer(const TimeDuration& timeout, const TimeDuration& interval, const function<void()>& func)
	{
		const CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, interval, TaskLifeToken());
		const Token token = MakeToken<FunctionToken>(bind(&Timer::RemoveTask, _queue, ci));

		{
			MutexLock l(_queue->Sync());
			_queue->Push(ci);
			_cond.Broadcast();
		}

		return token;
	}

	void Timer::AddTask(const function<void()>& task, const FutureExecutionTester& tester)
	{
		const CallbackInfoPtr ci = make_shared<CallbackInfo>(MakeCancellableFunction(task, tester), _monotonic.Elapsed(), null, TaskLifeToken::CreateDummyTaskToken());

		MutexLock l(_queue->Sync());
		_queue->Push(ci);
		_cond.Broadcast();
	}

	void Timer::RemoveTask(const CallbackQueuePtr& queue, const CallbackInfoPtr& ci)
	{
		{
			MutexLock l(queue->Sync());
			queue->Erase(ci);
		}
		ci->Release();
	}

	void Timer::DefaultExceptionHandler(const std::exception& ex)
	{ s_logger.Error() << "Timer func exception: " << ex; }

	std::string Timer::GetProfilerMessage(const function<void()>& func) const
	{ return StringBuilder() % get_function_name(func) % " in Timer '" % _timerName % "'"; }

	void Timer::ThreadFunc(const ICancellationToken& token)
	{
		MutexLock l(_queue->Sync());

		while (token)
		{
			if (_queue->IsEmpty())
			{
				_cond.Wait(_queue->Sync(), token);
				continue;
			}

			CallbackInfoPtr top = _queue->Top();
			if (top->GetTimeToTrigger() <= _monotonic.Elapsed())
			{
				_queue->Pop();

				MutexUnlock ul(l);

				const optional<TimeDuration> monotonic = top->IsPeriodic() ? _monotonic.Elapsed() : optional<TimeDuration>();

				ExecuteTask(top);

				if (monotonic)
				{
					top->Restart(*monotonic);
					_queue->Push(top);
				}

				top.reset();
			}
			else //top timer not triggered
			{
				const TimeDuration waitTime = top->GetTimeToTrigger() - _monotonic.Elapsed();
				top.reset();
				if (waitTime > TimeDuration())
					_cond.TimedWait(_queue->Sync(), waitTime, token);
			}
		}

		const TimeDuration currentTime = _monotonic.Elapsed();
		while (!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Top();

			if (top->GetTimeToTrigger() > currentTime)
				break;

			_queue->Pop();

			MutexUnlock ul(l);

			ExecuteTask(top);
			top.reset();
		}
	}

	void Timer::ExecuteTask(const CallbackInfoPtr& ci) const
	{
		LocalExecutionGuard guard(ci->GetExecutionTester());
		if (!guard)
			return;

		try
		{
			if (_profileTimeout)
			{
				AsyncProfiler::Session profiler_session(ExecutorsProfiler::Instance().GetProfiler(), bind(&Timer::GetProfilerMessage, this, ref(ci->GetFunc())), _profileTimeout->GetMilliseconds(), AsyncProfiler::Session::NameGetterTag());
				ci->GetFunc()();
			}
			else
				ci->GetFunc()();
		}
		catch(const std::exception &ex)
		{ _exceptionHandler(ex); }
	}

}
<commit_msg>Timer: execute exception handler outside task's life token<commit_after>// Copyright (c) 2011 - 2017, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/timer/Timer.h>

#include <stingraykit/diagnostics/ExecutorsProfiler.h>
#include <stingraykit/function/CancellableFunction.h>
#include <stingraykit/function/bind.h>
#include <stingraykit/function/function_name_getter.h>
#include <stingraykit/log/Logger.h>
#include <stingraykit/time/ElapsedTime.h>
#include <stingraykit/FunctionToken.h>
#include <stingraykit/TaskLifeToken.h>

#include <list>
#include <map>

namespace stingray
{

	class Timer::CallbackQueue
	{
		typedef std::list<CallbackInfoPtr>					ContainerInternal;
		typedef std::map<TimeDuration, ContainerInternal>	Container;

	private:
		Mutex			_mutex;
		Container		_container;

	public:
		typedef ContainerInternal::iterator iterator;

		inline Mutex& Sync()
		{ return _mutex; }

		inline bool IsEmpty() const
		{
			MutexLock l(_mutex);
			return _container.empty();
		}

		CallbackInfoPtr Top() const;
		void Push(const CallbackInfoPtr& ci);
		void Erase(const CallbackInfoPtr& ci);
		CallbackInfoPtr Pop();
	};

	class Timer::CallbackInfo
	{
		STINGRAYKIT_NONCOPYABLE(CallbackInfo);

		typedef function<void()>			FuncT;
		typedef CallbackQueue::iterator		QueueIterator;

	private:
		FuncT						_func;
		TimeDuration				_timeToTrigger;
		optional<TimeDuration>		_period;
		TaskLifeToken				_token;

		bool						_erased;
		optional<QueueIterator>		_iterator;

	private:
		friend class CallbackQueue;

		void SetIterator(const optional<QueueIterator>& it)		{ _iterator = it; }
		const optional<QueueIterator>& GetIterator() const		{ return _iterator; }
		void SetErased()										{ _erased = true; }
		bool IsErased() const									{ return _erased; }

	public:
		CallbackInfo(const FuncT& func, const TimeDuration& timeToTrigger, const optional<TimeDuration>& period, const TaskLifeToken& token)
			:	_func(func),
				_timeToTrigger(timeToTrigger),
				_period(period),
				_token(token),
				_erased(false)
		{ }

		const FuncT& GetFunc() const							{ return _func; }
		FutureExecutionTester GetExecutionTester() const 		{ return _token.GetExecutionTester(); }
		void Release()											{ _token.Release(); }

		bool IsPeriodic() const									{ return _period; }
		void Restart(const TimeDuration& currentTime)
		{
			STINGRAYKIT_CHECK(_period, "CallbackInfo::Restart internal error: _period is set!");
			_timeToTrigger = currentTime + *_period;
		}
		TimeDuration GetTimeToTrigger() const					{ return _timeToTrigger; }
	};

	Timer::CallbackInfoPtr Timer::CallbackQueue::Top() const
	{
		MutexLock l(_mutex);
		if (!_container.empty())
		{
			const ContainerInternal& listForTop = _container.begin()->second;
			STINGRAYKIT_CHECK(!listForTop.empty(), "try to get callback from empty list");
			return listForTop.front();
		}
		else
			return null;
	}

	void Timer::CallbackQueue::Push(const CallbackInfoPtr& ci)
	{
		MutexLock l(_mutex);
		if (ci->IsErased())
			return;

		ContainerInternal& listToInsert = _container[ci->GetTimeToTrigger()];
		ci->SetIterator(listToInsert.insert(listToInsert.end(), ci));
	}

	void Timer::CallbackQueue::Erase(const CallbackInfoPtr& ci)
	{
		MutexLock l(_mutex);
		ci->SetErased();

		const optional<iterator>& it = ci->GetIterator();
		if (!it)
			return;

		TimeDuration keyToErase = ci->GetTimeToTrigger();
		ContainerInternal& listToErase = _container[keyToErase];
		listToErase.erase(*it);
		if (listToErase.empty())
			_container.erase(keyToErase);
		ci->SetIterator(null);
	}

	Timer::CallbackInfoPtr Timer::CallbackQueue::Pop()
	{
		MutexLock l(_mutex);
		STINGRAYKIT_CHECK(!_container.empty(), "popping callback from empty map");
		ContainerInternal& listToPop = _container.begin()->second;
		STINGRAYKIT_CHECK(!listToPop.empty(), "popping callback from empty list");

		CallbackInfoPtr ci = listToPop.front();
		listToPop.pop_front();
		if (listToPop.empty())
			_container.erase(ci->GetTimeToTrigger());
		ci->SetIterator(null);
		return ci;
	}

	STINGRAYKIT_DEFINE_NAMED_LOGGER(Timer);

	const TimeDuration Timer::DefaultProfileTimeout = TimeDuration::FromSeconds(10);

	Timer::Timer(const std::string& timerName, const optional<TimeDuration>& profileTimeout, const ExceptionHandler& exceptionHandler)
		:	_timerName(timerName),
			_profileTimeout(profileTimeout),
			_exceptionHandler(exceptionHandler),
			_queue(make_shared<CallbackQueue>()),
			_worker(make_shared<Thread>(timerName, bind(&Timer::ThreadFunc, this, _1)))
	{ }

	Timer::~Timer()
	{
		_worker.reset();

		MutexLock l(_queue->Sync());
		if (!_queue->IsEmpty())
			s_logger.Warning() << "killing timer " << _timerName << " which still has some functions to execute";

		while(!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Pop();
			MutexUnlock ul(l);
			top.reset();
		}
	}

	Token Timer::SetTimeout(const TimeDuration& timeout, const function<void()>& func)
	{
		const CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, null, TaskLifeToken());
		const Token token = MakeToken<FunctionToken>(bind(&Timer::RemoveTask, _queue, ci));

		{
			MutexLock l(_queue->Sync());
			_queue->Push(ci);
			_cond.Broadcast();
		}

		return token;
	}

	Token Timer::SetTimer(const TimeDuration& interval, const function<void()>& func)
	{ return SetTimer(interval, interval, func); }

	Token Timer::SetTimer(const TimeDuration& timeout, const TimeDuration& interval, const function<void()>& func)
	{
		const CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, interval, TaskLifeToken());
		const Token token = MakeToken<FunctionToken>(bind(&Timer::RemoveTask, _queue, ci));

		{
			MutexLock l(_queue->Sync());
			_queue->Push(ci);
			_cond.Broadcast();
		}

		return token;
	}

	void Timer::AddTask(const function<void()>& task, const FutureExecutionTester& tester)
	{
		const CallbackInfoPtr ci = make_shared<CallbackInfo>(MakeCancellableFunction(task, tester), _monotonic.Elapsed(), null, TaskLifeToken::CreateDummyTaskToken());

		MutexLock l(_queue->Sync());
		_queue->Push(ci);
		_cond.Broadcast();
	}

	void Timer::RemoveTask(const CallbackQueuePtr& queue, const CallbackInfoPtr& ci)
	{
		{
			MutexLock l(queue->Sync());
			queue->Erase(ci);
		}
		ci->Release();
	}

	void Timer::DefaultExceptionHandler(const std::exception& ex)
	{ s_logger.Error() << "Timer func exception: " << ex; }

	std::string Timer::GetProfilerMessage(const function<void()>& func) const
	{ return StringBuilder() % get_function_name(func) % " in Timer '" % _timerName % "'"; }

	void Timer::ThreadFunc(const ICancellationToken& token)
	{
		MutexLock l(_queue->Sync());

		while (token)
		{
			if (_queue->IsEmpty())
			{
				_cond.Wait(_queue->Sync(), token);
				continue;
			}

			CallbackInfoPtr top = _queue->Top();
			if (top->GetTimeToTrigger() <= _monotonic.Elapsed())
			{
				_queue->Pop();

				MutexUnlock ul(l);

				const optional<TimeDuration> monotonic = top->IsPeriodic() ? _monotonic.Elapsed() : optional<TimeDuration>();

				ExecuteTask(top);

				if (monotonic)
				{
					top->Restart(*monotonic);
					_queue->Push(top);
				}

				top.reset();
			}
			else //top timer not triggered
			{
				const TimeDuration waitTime = top->GetTimeToTrigger() - _monotonic.Elapsed();
				top.reset();
				if (waitTime > TimeDuration())
					_cond.TimedWait(_queue->Sync(), waitTime, token);
			}
		}

		const TimeDuration currentTime = _monotonic.Elapsed();
		while (!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Top();

			if (top->GetTimeToTrigger() > currentTime)
				break;

			_queue->Pop();

			MutexUnlock ul(l);

			ExecuteTask(top);
			top.reset();
		}
	}

	void Timer::ExecuteTask(const CallbackInfoPtr& ci) const
	{
		try
		{
			LocalExecutionGuard guard(ci->GetExecutionTester());
			if (!guard)
				return;

			if (_profileTimeout)
			{
				AsyncProfiler::Session profiler_session(ExecutorsProfiler::Instance().GetProfiler(), bind(&Timer::GetProfilerMessage, this, ref(ci->GetFunc())), _profileTimeout->GetMilliseconds(), AsyncProfiler::Session::NameGetterTag());
				ci->GetFunc()();
			}
			else
				ci->GetFunc()();
		}
		catch(const std::exception &ex)
		{ _exceptionHandler(ex); }
	}

}
<|endoftext|>


<commit_before>// Aho Corasick - <O(sum(m)), O(n + #matches)>
// Multiple string matching

int p[N], f[N], nxt[N][26], ch[N];
int tsz=1; // size of the trie

int cnt[N]; // used to know number of matches

// used to know which strings matches.
// S is the number of strings. Can use set instead
const int S = 2e3+5;
bitset<S> elem[N];

void init() {
  tsz=1;
  memset(f, 0, sizeof(f));
  memset(nxt, 0, sizeof(nxt));
  memset(cnt, 0, sizeof(cnt));
  for (int i = 0; i < N; i++) elem[i].reset();
}

void add(const string &s, int x) {
  int cur = 1; // the first element of the trie is the root

  for (int i=0; s[i]; ++i) {
    int j = s[i] - 'a';
    if (!nxt[cur][j]) {
      tsz++;
      p[tsz] = cur;
      ch[tsz] = j;
      nxt[cur][j] = tsz;
    }
    cur = nxt[cur][j];
  }

  cnt[cur]++; //
  elem[cur].set(x);
}

void build() {
  queue<int> q;

  for(int i=0; i<26; ++i) {
    nxt[0][i] = 1;
    if (nxt[1][i]) q.push(nxt[1][i]);
  }

  while (!q.empty()) {
    int v = q.front(); q.pop();
    int u = f[p[v]];

    while (u and !nxt[u][ch[v]]) u = f[u];
    f[v] = nxt[u][ch[v]];
    cnt[v] += cnt[f[v]];
    elem[v] |= elem[f[v]];

    for (int i = 0; i < 26; ++i) {
      if (nxt[v][i]) q.push(nxt[v][i]);
      /* Pre-Computation of next states
      else {
        int ax = f[v];
        while(ax and !nxt[ax][i]) ax = f[ax];
        nxt[v][i] = nxt[ax][i];
      }
      */
    }
  }
}

// Return ans to get number of matches
// Return a map (or global array) if want to know how many of each string have matched
bitset<S> match(char *s) {
  int ans = 0;    // used to know the number of matches
  bitset<S> found; // used to know which strings matches

  int x = 1;
  for (int i = 0; s[i]; ++i) {
    int t = s[i] - 'a';
    while (x and !nxt[x][t]) x = f[x];
    x = nxt[x][t];

    // match found
    ans += cnt[x];
    found |= elem[x];
  }

  return found;
}

<commit_msg>Update aho.cpp<commit_after>// Aho Corasick - <O(sum(m)), O(n + #matches)>
// Multiple string matching

int p[N], f[N], nxt[N][26], ch[N];
int tsz=1; // size of the trie

int cnt[N]; // used to know number of matches

// used to know which strings matches.
// S is the number of strings. Can use set instead
const int S = 2e3+5;
bitset<S> elem[N];

void init() {
  tsz=1;
  memset(f, 0, sizeof(f));
  memset(nxt, 0, sizeof(nxt));
  memset(cnt, 0, sizeof(cnt));
  for (int i = 0; i < N; i++) elem[i].reset();
}

void add(const string &s, int x) {
  int cur = 1; // the first element of the trie is the root

  for (int i=0; s[i]; ++i) {
    int j = s[i] - 'a';
    if (!nxt[cur][j]) {
      tsz++;
      p[tsz] = cur;
      ch[tsz] = j;
      nxt[cur][j] = tsz;
    }
    cur = nxt[cur][j];
  }

  cnt[cur]++; //
  elem[cur].set(x);
}

void build() {
  queue<int> q;

  for(int i=0; i<26; ++i) {
    nxt[0][i] = 1;
    if (nxt[1][i]) q.push(nxt[1][i]);
  }

  while (!q.empty()) {
    int v = q.front(); q.pop();
    int u = f[p[v]];

    while (u and !nxt[u][ch[v]]) u = f[u];
    f[v] = nxt[u][ch[v]];
    cnt[v] += cnt[f[v]];
    elem[v] |= elem[f[v]];

    for (int i = 0; i < 26; ++i) {
      if (nxt[v][i]) q.push(nxt[v][i]);
      else nxt[v][i] = nxt[f[v]][i];
    }
  }
}

// Return ans to get number of matches
// Return a map (or global array) if want to know how many of each string have matched
bitset<S> match(char *s) {
  int ans = 0;    // used to know the number of matches
  bitset<S> found; // used to know which strings matches

  int x = 1;
  for (int i = 0; s[i]; ++i) {
    int t = s[i] - 'a';
    x = nxt[x][t];

    // match found
    ans += cnt[x];
    found |= elem[x];
  }

  return found;
}

<|endoftext|>


<commit_before>/* **** **** **** **** **** **** **** **** *
 *
 *         _/        _/        _/
 *        _/_/_/    _/_/_/    _/_/_/
 *       _/    _/  _/    _/  _/    _/
 *      _/    _/  _/    _/  _/    _/
 *     _/_/_/    _/_/_/    _/_/_/
 *
 * bit by bit
 * type_utils.hpp
 *
 * author: ISHII 2bit
 * mail:   2bit@backspace.tokyo
 *
 * **** **** **** **** **** **** **** **** */

#pragma once

#include "constants.hpp"

#include <type_traits>
#include <tuple>
#include <functional>

namespace bbb {
	template <typename T>
	using get_type = typename T::type;

	template <bool b, typename T = void>
	using enable_if = get_type<std::enable_if<b, T>>;

    template <bool b, typename T, typename F>
    using conditional = get_type<std::conditional<b, T, F>>;

	template <typename T>
	constexpr bool is_const() {
		return std::is_const<T>::value;
	}

	template <typename T>
	constexpr bool is_number() {
		return std::is_arithmetic<T>::value;
	}

	template <typename T>
	constexpr bool is_integer() {
		return std::is_integral<T>::value;
	}

	template <typename T>
	constexpr bool is_float() {
		return std::is_floating_point<T>::value;
	}

	template <typename T>
	using remove_const_reference_if_number = get_type<std::conditional<
		is_number<T>(),
		get_type<std::remove_reference<
			get_type<std::remove_const<T>>
		>>,
		T
	>>;

	template <typename T>
	using add_const_reference_if_not_number = get_type<std::conditional<
		!is_number<T>(),
		get_type<std::add_const<
			get_type<std::add_lvalue_reference<T>>
		>>,
		T
	>>;

	namespace function_traits {
		template <typename T>
		struct function_info : public function_info<decltype(&T::operator())> {};

		template <typename class_type, typename ret, typename ... arguments>
		struct function_info<ret(class_type::*)(arguments ...) const> {
			static constexpr std::size_t arity = sizeof...(arguments);
			using result_type = ret;
			using arguments_types_tuple = std::tuple<arguments ...>;
			template <std::size_t index>
			using argument_type = get_type<std::tuple_element<index, arguments_types_tuple>>;
			using function_type = std::function<ret(arguments ...)>;
		};

		template <typename class_type, typename ret, typename ... arguments>
		struct function_info<ret(class_type::*)(arguments ...)> {
			static constexpr std::size_t arity = sizeof...(arguments);
			using result_type = ret;
			using arguments_types_tuple = std::tuple<arguments ...>;
			template <std::size_t index>
			using argument_type = get_type<std::tuple_element<index, arguments_types_tuple>>;
			using function_type = std::function<ret(arguments ...)>;
		};

		template <typename ret, typename ... arguments>
		struct function_info<ret(*)(arguments ...)> {
			static constexpr std::size_t arity = sizeof...(arguments);
			using result_type = ret;
			using arguments_types_tuple = std::tuple<arguments ...>;
			template <std::size_t index>
			using argument_type = get_type<std::tuple_element<index, arguments_types_tuple>>;
			using function_type = std::function<ret(arguments ...)>;
		};

		template<typename T>
		using result_type = typename function_info<T>::result_type;

		template<typename T>
		using arguments_types_tuple = typename function_info<T>::arguments_types_tuple;

		template<typename T, std::size_t index>
		using argument_type = typename function_info<T>::template argument_type<index>;

		template<typename T>
		struct arity {
			static constexpr std::size_t value = function_info<T>::arity;
		};

		template <typename patient>
		struct has_call_operator {
			template <typename inner_patient, decltype(&inner_patient::operator())> struct checker {};
			template <typename inner_patient> static std::true_type  check(checker<inner_patient, &inner_patient::operator()> *);
			template <typename>               static std::false_type check(...);
			using type = decltype(check<patient>(nullptr));
			static constexpr bool value = type::value;
		};

		template <typename patient>
		constexpr bool is_callable(const patient &) {
			return std::is_function<patient>::value || has_call_operator<patient>::value;
		};
	};
	using namespace function_traits;

	namespace sequences {
		template <typename type, type ... ns>
		struct integer_sequence {
			using value_type = type;
			static constexpr std::size_t size() noexcept { return sizeof...(ns); }
		};

		namespace impl {
			template <typename integer_type, integer_type n, integer_type ... ns>
			struct make_integer_sequence {
				struct sequence_wrapper { using type = integer_sequence<integer_type, ns ...>; };
				using type = get_type<conditional<
					n == 0,
					sequence_wrapper,
					impl::make_integer_sequence<integer_type, n - 1, n - 1, ns ...>
				>>;
			};
		};

		template <typename type, type n>
		using make_integer_sequence = impl::make_integer_sequence<type, n>;

		template <std::size_t ... ns>
		using index_sequence = integer_sequence<std::size_t, ns ...>;

		template <std::size_t n>
		using make_index_sequence = make_integer_sequence<std::size_t, n>;

		template <typename... types>
		using index_sequence_for = make_index_sequence<sizeof...(types)>;
	};
	using namespace sequences;

	namespace functional_utilities {
		namespace impl {
			template <typename return_value_t, typename ... arguments, std::size_t ... indicies>
			return_value_t apply(std::function<return_value_t(arguments ...)> f, std::tuple<arguments ...> t, index_sequence<indicies ...>) {
				return f(std::get<indicies>(t) ...);
			};
		};
		template <typename return_value_t, typename ... arguments>
		return_value_t apply(std::function<return_value_t(arguments ...)> f, std::tuple<arguments ...> t) {
			return impl::apply(f, t, get_type<index_sequence_for<arguments ...>>());
		}
		template <typename function_t, typename ... arguments>
		typename function_info<function_t>::result_type apply(function_t f, std::tuple<arguments ...> t) {
			return impl::apply(static_cast<typename function_info<function_t>::function_type>(f), t, get_type<make_index_sequence<function_info<function_t>::arity>>());
		}
	};
	using namespace functional_utilities;
};<commit_msg>add is_same()<commit_after>/* **** **** **** **** **** **** **** **** *
 *
 *         _/        _/        _/
 *        _/_/_/    _/_/_/    _/_/_/
 *       _/    _/  _/    _/  _/    _/
 *      _/    _/  _/    _/  _/    _/
 *     _/_/_/    _/_/_/    _/_/_/
 *
 * bit by bit
 * type_utils.hpp
 *
 * author: ISHII 2bit
 * mail:   2bit@backspace.tokyo
 *
 * **** **** **** **** **** **** **** **** */

#pragma once

#include "constants.hpp"

#include <type_traits>
#include <tuple>
#include <functional>

namespace bbb {
	template <typename T>
	using get_type = typename T::type;

	template <bool b, typename T = void>
	using enable_if = get_type<std::enable_if<b, T>>;

    template <bool b, typename T, typename F>
    using conditional = get_type<std::conditional<b, T, F>>;

	template <typename T, typename U>
	constexpr bool is_same() { return std::is_same<T, U>::value; };

	template <typename T>
	constexpr bool is_const() {
		return std::is_const<T>::value;
	}

	template <typename T>
	constexpr bool is_number() {
		return std::is_arithmetic<T>::value;
	}

	template <typename T>
	constexpr bool is_integer() {
		return std::is_integral<T>::value;
	}

	template <typename T>
	constexpr bool is_float() {
		return std::is_floating_point<T>::value;
	}

	template <typename T>
	using remove_const_reference_if_number = get_type<std::conditional<
		is_number<T>(),
		get_type<std::remove_reference<
			get_type<std::remove_const<T>>
		>>,
		T
	>>;

	template <typename T>
	using add_const_reference_if_not_number = get_type<std::conditional<
		!is_number<T>(),
		get_type<std::add_const<
			get_type<std::add_lvalue_reference<T>>
		>>,
		T
	>>;

	namespace function_traits {
		template <typename T>
		struct function_info : public function_info<decltype(&T::operator())> {};

		template <typename class_type, typename ret, typename ... arguments>
		struct function_info<ret(class_type::*)(arguments ...) const> {
			static constexpr std::size_t arity = sizeof...(arguments);
			using result_type = ret;
			using arguments_types_tuple = std::tuple<arguments ...>;
			template <std::size_t index>
			using argument_type = get_type<std::tuple_element<index, arguments_types_tuple>>;
			using function_type = std::function<ret(arguments ...)>;
		};

		template <typename class_type, typename ret, typename ... arguments>
		struct function_info<ret(class_type::*)(arguments ...)> {
			static constexpr std::size_t arity = sizeof...(arguments);
			using result_type = ret;
			using arguments_types_tuple = std::tuple<arguments ...>;
			template <std::size_t index>
			using argument_type = get_type<std::tuple_element<index, arguments_types_tuple>>;
			using function_type = std::function<ret(arguments ...)>;
		};

		template <typename ret, typename ... arguments>
		struct function_info<ret(*)(arguments ...)> {
			static constexpr std::size_t arity = sizeof...(arguments);
			using result_type = ret;
			using arguments_types_tuple = std::tuple<arguments ...>;
			template <std::size_t index>
			using argument_type = get_type<std::tuple_element<index, arguments_types_tuple>>;
			using function_type = std::function<ret(arguments ...)>;
		};

		template<typename T>
		using result_type = typename function_info<T>::result_type;

		template<typename T>
		using arguments_types_tuple = typename function_info<T>::arguments_types_tuple;

		template<typename T, std::size_t index>
		using argument_type = typename function_info<T>::template argument_type<index>;

		template<typename T>
		struct arity {
			static constexpr std::size_t value = function_info<T>::arity;
		};

		template <typename patient>
		struct has_call_operator {
			template <typename inner_patient, decltype(&inner_patient::operator())> struct checker {};
			template <typename inner_patient> static std::true_type  check(checker<inner_patient, &inner_patient::operator()> *);
			template <typename>               static std::false_type check(...);
			using type = decltype(check<patient>(nullptr));
			static constexpr bool value = type::value;
		};

		template <typename patient>
		constexpr bool is_callable(const patient &) {
			return std::is_function<patient>::value || has_call_operator<patient>::value;
		};
	};
	using namespace function_traits;

	namespace sequences {
		template <typename type, type ... ns>
		struct integer_sequence {
			using value_type = type;
			static constexpr std::size_t size() noexcept { return sizeof...(ns); }
		};

		namespace impl {
			template <typename integer_type, integer_type n, integer_type ... ns>
			struct make_integer_sequence {
				struct sequence_wrapper { using type = integer_sequence<integer_type, ns ...>; };
				using type = get_type<conditional<
					n == 0,
					sequence_wrapper,
					impl::make_integer_sequence<integer_type, n - 1, n - 1, ns ...>
				>>;
			};
		};

		template <typename type, type n>
		using make_integer_sequence = impl::make_integer_sequence<type, n>;

		template <std::size_t ... ns>
		using index_sequence = integer_sequence<std::size_t, ns ...>;

		template <std::size_t n>
		using make_index_sequence = make_integer_sequence<std::size_t, n>;

		template <typename... types>
		using index_sequence_for = make_index_sequence<sizeof...(types)>;
	};
	using namespace sequences;

	namespace functional_utilities {
		namespace impl {
			template <typename return_value_t, typename ... arguments, std::size_t ... indicies>
			return_value_t apply(std::function<return_value_t(arguments ...)> f, std::tuple<arguments ...> t, index_sequence<indicies ...>) {
				return f(std::get<indicies>(t) ...);
			};
		};
		template <typename return_value_t, typename ... arguments>
		return_value_t apply(std::function<return_value_t(arguments ...)> f, std::tuple<arguments ...> t) {
			return impl::apply(f, t, get_type<index_sequence_for<arguments ...>>());
		}
		template <typename function_t, typename ... arguments>
		typename function_info<function_t>::result_type apply(function_t f, std::tuple<arguments ...> t) {
			return impl::apply(static_cast<typename function_info<function_t>::function_type>(f), t, get_type<make_index_sequence<function_info<function_t>::arity>>());
		}
	};
	using namespace functional_utilities;
};<|endoftext|>


<commit_before>#include <iostream>
#include <seqan/seq_io.h>
#include "fasta_stats.h"
#include "error.h"

using namespace seqan;
using namespace std;

FastaStats::FastaStats(void)
{
    num_seqs = 0;
    num_bases = 0;
    min_len = 0;
    max_len = 0;
}

FastaStats::FastaStats (unsigned int ns, unsigned int nb, unsigned int mnl, unsigned int mxl):
    num_seqs(ns), num_bases(nb), min_len(mnl), max_len(mxl) {}

bool operator== (const FastaStats &stats1, const FastaStats &stats2)
{
    return stats1.num_seqs == stats2.num_seqs &&
           stats1.num_bases == stats2.num_bases &&
           stats1.min_len == stats2.min_len &&
           stats1.max_len == stats2.max_len;
}

ostream& operator<< (ostream &out, const FastaStats &stats)
{
    out << "FastaStats("
	<< stats.num_seqs << ", "
        << stats.num_bases << ", "
        << stats.min_len << ", "
        << stats.max_len << ")";
    return out;
}

string FastaStats::pretty(string filename)
{
    ostringstream result;

    if(num_seqs > 0)
    {
        unsigned average = num_bases / num_seqs;

        result << filename << "\t"
               << num_seqs << "\t"
               << num_bases << "\t"
               << min_len << "\t"
               << average << "\t"
               << max_len;
    }
    else
    {
        result << filename << "\t0\t0\t-\t-\t-";
    }

    return result.str();
}

void FastaStats::from_file(SeqFileIn &seq_file_in, unsigned minlen_threshold)
{
    unsigned this_len;
    CharString id;
    CharString seq;

    while(!atEnd(seq_file_in))
    {
        try
        {
            readRecord(id, seq, seq_file_in);
        }
        catch (Exception const & e)
        {
	    exit_with_error(e.what(), Error_parse_file);
        }
        this_len = length(seq);
        if (this_len >= minlen_threshold)
        {
            if (num_seqs == 0)
            {
                min_len = max_len = this_len;
            }
            else
            {
                min_len = min(min_len, this_len);
                max_len = max(max_len, this_len);
            }
            num_seqs++;
            num_bases += this_len;
        }
    }
}
<commit_msg>Add more comments to CPP version<commit_after>/*
File:       : fasta_stats.cpp
Description : Compute various statistics about a FASTA file.
Copyright   : (c) Bernie Pope, 2016
License     : MIT
Maintainer  : bjpope@unimelb.edu.au
Stability   : stable
Portability : POSIX
*/

#include <iostream>
#include <seqan/seq_io.h>
#include "fasta_stats.h"
#include "error.h"

using namespace seqan;
using namespace std;

/*
    Construct an initial empty FastaStats object.
    All counters set to zero.
*/
FastaStats::FastaStats(void)
{
    num_seqs = 0;
    num_bases = 0;
    min_len = 0;
    max_len = 0;
}

/*
    Construct an initial non-empty FastaStats object.
    All counters set to their corresponding parameters.

    arguments:
        ns: number of sequences in FASTA file
        nb: number of bases in FASTA file over all sequences
        mnl: minimum length of a sequence in the FASTA file
        mxl: maximum length of a sequence in the FASTA file
*/
FastaStats::FastaStats (unsigned int ns, unsigned int nb, unsigned int mnl, unsigned int mxl):
    num_seqs(ns), num_bases(nb), min_len(mnl), max_len(mxl) {}

/*
    Compare two FastaStats objects for equality.
    The objects are considered equal if all their attributes are equal.

    arguments:
        stats1: reference to first FastaStats object
        stats2: reference to second FastaStats object
    result:
        boolean, true if the two input FastaStats objects are equal, false
        otherwise
*/
bool operator== (const FastaStats &stats1, const FastaStats &stats2)
{
    return stats1.num_seqs == stats2.num_seqs &&
           stats1.num_bases == stats2.num_bases &&
           stats1.min_len == stats2.min_len &&
           stats1.max_len == stats2.max_len;
}

/*
    Print a FastaStats object on an output stream.

    arguments:
        out: reference to output stream
        stats: reference to a FastaStats object to print
    result:
       output stream, useful for chaining output expressions.
*/
ostream& operator<< (ostream &out, const FastaStats &stats)
{
    out << "FastaStats("
	<< stats.num_seqs << ", "
        << stats.num_bases << ", "
        << stats.min_len << ", "
        << stats.max_len << ")";
    return out;
}

/*
    Render a FastaStats object as a string in a format required
    by biotool. The average length of sequences is computed at this
    point, and included in the output.

    The fields in the output are tab separated.

    If the number of counted sequences is not > 0, num_seqs and
    num_bases are displayed as 0, and the remaining fields are
    rendered as dashes (-) to indicate that their values are not
    available.

    arguments:
        filename: identifier for the file (or stream) from which the
            FASTA object was read (could be a filename or "stdin")
    result:
       string: rendering of the FastaStats object
*/
string FastaStats::pretty(string filename)
{
    ostringstream result;

    if(num_seqs > 0)
    {
        // Average sequence length, rounded down towards 0
        unsigned average = num_bases / num_seqs;

        result << filename << "\t"
               << num_seqs << "\t"
               << num_bases << "\t"
               << min_len << "\t"
               << average << "\t"
               << max_len;
    }
    else
    {
        result << filename << "\t0\t0\t-\t-\t-";
    }

    return result.str();
}

/*

    Compute FastaStats from an input file.

    arguments:
        seq_file_in: reference to input FASTA file, as SeqFileIn from seqan
            library
        minlen_threshold: minimum length of sequence to be considered for
            counting. Sequenecs with lengths strictly below the threshold will
            be ignored, and not included in the resulting statistics.
    result:
       FastaStats object representing the computed statistics
*/
void FastaStats::from_file(SeqFileIn &seq_file_in, unsigned minlen_threshold)
{
    unsigned this_len;
    CharString id;
    CharString seq;

    // Read all sequences from the input FASTA file, one at a time
    while(!atEnd(seq_file_in))
    {
        // Parse the next sequence header and value
        try
        {
            readRecord(id, seq, seq_file_in);
        }
        // Exit if any parse errors are encountered
        catch (Exception const &e)
        {
	    exit_with_error(e.what(), Error_parse_file);
        }
        // Skip sequences whose length is less than threshold
        this_len = length(seq);
        if (this_len >= minlen_threshold)
        {
            // We haven't seen any sequences yet, so initialise
            // min_len and max_len to the length of this sequence
            if (num_seqs == 0)
            {
                min_len = max_len = this_len;
            }
            // We seen at least one sequence before, update
            // min_len and max_len
            else
            {
                min_len = min(min_len, this_len);
                max_len = max(max_len, this_len);
            }
            // Update sequence count and base count
            num_seqs++;
            num_bases += this_len;
        }
    }
}
<|endoftext|>