<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/. *//*
 * Created by Alexandre GAUTHIER-FOICHAT on 6/1/2012.
 * contact: immarespond at gmail dot com
 *
 */

#include "InfoViewerWidget.h"

#include <cstdlib>
#include <iostream>
#include <QtGui/QImage>
#include <QHBoxLayout>
#include <QLabel>
#include <QThread>
#include <QPaintEvent>
#include <QPainter>
#include <QCoreApplication>

#include "Engine/ViewerInstance.h"
#include "Engine/Lut.h"
#include "Engine/Image.h"
#include "Gui/ViewerGL.h"

using std::cout; using std::endl;
using namespace Natron;

InfoViewerWidget::InfoViewerWidget(ViewerGL* v,
                                   const QString & description,
                                   QWidget* parent)
    : QWidget(parent)
      , viewer(v)
      , _comp(eImageComponentNone)
{

    setFixedHeight(20);
    setStyleSheet( QString("background :black") );

    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

    layout = new QHBoxLayout(this);
    layout->setSpacing(0);
    layout->setContentsMargins(0, 0, 0, 0);

    descriptionLabel = new QLabel(this);
    {
        const QFont& font = descriptionLabel->font();

        QString descriptionText = QString("")
        .arg(font.family())
        .arg(font.pixelSize());
        descriptionText.append(description);
        descriptionText.append("");
        descriptionLabel->setText(descriptionText);
        QFontMetrics fm = descriptionLabel->fontMetrics();
        int width = fm.width("A:");
        descriptionLabel->setMinimumWidth(width);
    }
    imageFormat = new QLabel(this);
    {
        QFontMetrics fm = imageFormat->fontMetrics();
        int width = fm.width("RGBA32f");
        imageFormat->setMinimumWidth(width);
    }

    resolution = new QLabel(this);
    {
        QFontMetrics fm = resolution->fontMetrics();
        int width = fm.width("00000x00000");
        resolution->setMinimumWidth(width);
    }

    coordDispWindow = new QLabel(this);
    {
        QFontMetrics fm = coordDispWindow->fontMetrics();
        int width = fm.width("RoD: 000 000 0000 0000");
        coordDispWindow->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
        coordDispWindow->setMinimumWidth(width);
    }

    _fpsLabel = new QLabel(this);
    {
        QFontMetrics fm = _fpsLabel->fontMetrics();
        int width = fm.width("100 fps");
        _fpsLabel->setMinimumWidth(width);
        _fpsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
        _fpsLabel->hide();
    }

    coordMouse = new QLabel(this);
    {
        QFontMetrics fm = coordMouse->fontMetrics();
        int width = fm.width("x=00000 y=00000");
        coordMouse->setMinimumWidth(width);
    }

    rgbaValues = new QLabel(this);
    {
        QFontMetrics fm = rgbaValues->fontMetrics();
        int width = fm.width("0.00000 0.00000 0.00000");
        rgbaValues->setMinimumWidth(width);
    }

    color = new QLabel(this);
    color->setFixedSize(20, 20);

    hvl_lastOption = new QLabel(this);
    {
        QFontMetrics fm = hvl_lastOption->fontMetrics();
        int width = fm.width("H:000 S:0.00 V:0.00 L:0.00000");
        hvl_lastOption->setMinimumWidth(width);
    }

    layout->addWidget(descriptionLabel);
    layout->addWidget(imageFormat);
    layout->addWidget(resolution);
    layout->addWidget(coordDispWindow);
    layout->addWidget(_fpsLabel);
    layout->addWidget(coordMouse);
    layout->addWidget(rgbaValues);
    layout->addWidget(color);
    layout->addWidget(hvl_lastOption);

}

QSize
InfoViewerWidget::sizeHint() const
{
    return QWidget::sizeHint();
}

QSize
InfoViewerWidget::minimumSizeHint() const
{
    return QWidget::minimumSizeHint();
}

void
InfoViewerWidget::setFps(double actualFps,
                         double desiredFps)
{
    QString colorStr("green");

    const QFont& font = _fpsLabel->font();

    if ( ( actualFps < (desiredFps -  desiredFps / 10.f) ) && ( actualFps > (desiredFps / 2.f) ) ) {
        colorStr = QString("orange");
    } else if ( actualFps < (desiredFps / 2.f) ) {
        colorStr = QString("red");
    }
    QString str = QString("%1 fps")
    .arg( QString::number(actualFps,'f',1) )
    .arg(font.family())
    .arg(font.pixelSize());

    _fpsLabel->setText(str);
    if ( !_fpsLabel->isVisible() ) {
        _fpsLabel->show();
    }
}

void
InfoViewerWidget::hideFps()
{
    if ( _fpsLabel->isVisible() ) {
        _fpsLabel->hide();
    }
}

bool
InfoViewerWidget::colorAndMouseVisible()
{
    return coordMouse->isVisible();
}

void
InfoViewerWidget::showColorAndMouseInfo()
{
    coordMouse->show();
    hvl_lastOption->show();
    rgbaValues->show();
    color->show();
}

void
InfoViewerWidget::hideColorAndMouseInfo()
{
    coordMouse->hide();
    hvl_lastOption->hide();
    rgbaValues->hide();
    color->hide();
}

InfoViewerWidget::~InfoViewerWidget()
{
}

void
InfoViewerWidget::setColor(float r,
                           float g,
                           float b,
                           float a)
{
    QString values;
    const QFont& font = rgbaValues->font();
    //values = QString("%1 %2 %3 %4")
    // the following three colors have an equal luminance (=0.4), which makes the text easier to read.
    switch (_comp) {
    case Natron::eImageComponentNone:
        values = QString();
        break;
    case Natron::eImageComponentAlpha:
        values = QString("%1")
            .arg(a,0,'f',5).arg(font.family()).arg(font.pixelSize());
        break;
    case Natron::eImageComponentRGB:
        values = QString("%1  "
                           "%2  "
                           "%3")
                   .arg(r,0,'f',5)
                   .arg(g,0,'f',5)
                   .arg(b,0,'f',5)
                   .arg(font.family())
                   .arg(font.pixelSize());
        break;
    case Natron::eImageComponentRGBA:
        values = QString("%1  "
                           "%2  "
                           "%3  "
                           "%4")
                   .arg(r,0,'f',5)
                   .arg(g,0,'f',5)
                   .arg(b,0,'f',5)
                   .arg(a,0,'f',5)
                   .arg(font.family())
                   .arg(font.pixelSize());
        break;
    }
    rgbaValues->setText(values);
    rgbaValues->repaint();
    float h,s,v,l;
    // Nuke's HSV display is based on sRGB, an L is Rec.709.
    // see http://forums.thefoundry.co.uk/phpBB2/viewtopic.php?t=2283
    double srgb_r = Color::to_func_srgb(r);
    double srgb_g = Color::to_func_srgb(g);
    double srgb_b = Color::to_func_srgb(b);
    QColor col;
    col.setRgbF( Natron::clamp(srgb_r), Natron::clamp(srgb_g), Natron::clamp(srgb_b) );
    QPixmap pix(15,15);
    pix.fill(col);
    color->setPixmap(pix);
    color->repaint();

    const QFont &hsvFont = hvl_lastOption->font();

    Color::rgb_to_hsv(srgb_r,srgb_g,srgb_b,&h,&s,&v);
    l = 0.2125 * r + 0.7154 * g + 0.0721 * b; // L according to Rec.709
    QString hsvlValues;
    hsvlValues = QString("H:%1 S:%2 V:%3  L:%4")
                 .arg(h,0,'f',0)
                 .arg(s,0,'f',2)
                 .arg(v,0,'f',2)
                 .arg(l,0,'f',5)
                 .arg(hsvFont.family())
                 .arg(hsvFont.pixelSize());

    hvl_lastOption->setText(hsvlValues);
    hvl_lastOption->repaint();
} // setColor

void
InfoViewerWidget::setMousePos(QPoint p)
{
    QString coord;
    const QFont& font = coordMouse->font();
    coord = QString("x=%1 y=%2")
            .arg( p.x() )
            .arg( p.y() )
            .arg(font.family())
            .arg(font.pixelSize());
    coordMouse->setText(coord);
}

void
InfoViewerWidget::setResolution(const Format & f)
{
    assert( QThread::currentThread() == qApp->thread() );
    format = f;

    const QFont& font = resolution->font();
    if ( format.getName() == std::string("") ) {
        QString reso;
        reso = QString("%1x%2")
        .arg( std::ceil(format.width()) )
        .arg( std::ceil(format.height()) )
        .arg(font.family())
        .arg(font.pixelSize());
        resolution->setText(reso);
    } else {
        QString reso = QString("")
        .arg(font.family())
        .arg(font.pixelSize());
        reso.append( format.getName().c_str() );
      //  reso.append("\t");
        reso.append("");
        resolution->setText(reso);
    }
}

void
InfoViewerWidget::setDataWindow(const RectD & r)
{
    QString bbox;
    const QFont& font = coordDispWindow->font();
    bbox = QString("RoD: %1 %2 %3 %4")
           .arg( std::ceil( r.left() ) )
           .arg( std::ceil( r.bottom() ) )
           .arg( std::floor( r.right() ) )
           .arg( std::floor( r.top() ) )
           .arg(font.family())
           .arg(font.pixelSize());

    coordDispWindow->setText(bbox);
}

void
InfoViewerWidget::setImageFormat(Natron::ImageComponentsEnum comp,
                                 Natron::ImageBitDepthEnum depth)
{

    const QFont& font = imageFormat->font();
    QString text = QString("")
    .arg(font.family())
    .arg(font.pixelSize());
    QString format(Natron::Image::getFormatString(comp, depth).c_str());
    text.append(format);
    text.append("");
    imageFormat->setText(text);
    _comp = comp;
}

void
InfoViewerWidget::paintEvent(QPaintEvent* e)
{
    QWidget::paintEvent(e);
}

<commit_msg>Oops ™<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/. *//*
 * Created by Alexandre GAUTHIER-FOICHAT on 6/1/2012.
 * contact: immarespond at gmail dot com
 *
 */

#include "InfoViewerWidget.h"

#include <cstdlib>
#include <iostream>
#include <QtGui/QImage>
#include <QHBoxLayout>
#include <QLabel>
#include <QThread>
#include <QPaintEvent>
#include <QPainter>
#include <QCoreApplication>

#include "Engine/ViewerInstance.h"
#include "Engine/Lut.h"
#include "Engine/Image.h"
#include "Gui/ViewerGL.h"

using std::cout; using std::endl;
using namespace Natron;

InfoViewerWidget::InfoViewerWidget(ViewerGL* v,
                                   const QString & description,
                                   QWidget* parent)
    : QWidget(parent)
      , viewer(v)
      , _comp(eImageComponentNone)
{

    setFixedHeight(20);
    setStyleSheet( QString("background :black") );

    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

    layout = new QHBoxLayout(this);
    layout->setSpacing(0);
    layout->setContentsMargins(0, 0, 0, 0);

    descriptionLabel = new QLabel(this);
    {
        const QFont& font = descriptionLabel->font();

        QString descriptionText = QString("")
        .arg(font.family())
        .arg(font.pixelSize());
        descriptionText.append(description);
        descriptionText.append("");
        descriptionLabel->setText(descriptionText);
        QFontMetrics fm = descriptionLabel->fontMetrics();
        int width = fm.width("A:");
        descriptionLabel->setMinimumWidth(width);
    }
    imageFormat = new QLabel(this);
    {
        QFontMetrics fm = imageFormat->fontMetrics();
        int width = fm.width("RGBA32f");
        imageFormat->setMinimumWidth(width);
    }

    resolution = new QLabel(this);
    {
        QFontMetrics fm = resolution->fontMetrics();
        int width = fm.width("00000x00000");
        resolution->setMinimumWidth(width);
    }

    coordDispWindow = new QLabel(this);
    {
        QFontMetrics fm = coordDispWindow->fontMetrics();
        int width = fm.width("RoD: 000 000 0000 0000");
        coordDispWindow->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
        coordDispWindow->setMinimumWidth(width);
    }

    _fpsLabel = new QLabel(this);
    {
        QFontMetrics fm = _fpsLabel->fontMetrics();
        int width = fm.width("100 fps");
        _fpsLabel->setMinimumWidth(width);
        _fpsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
        _fpsLabel->hide();
    }

    coordMouse = new QLabel(this);
    {
        QFontMetrics fm = coordMouse->fontMetrics();
        int width = fm.width("x=00000 y=00000");
        coordMouse->setMinimumWidth(width);
    }

    rgbaValues = new QLabel(this);
    {
        QFontMetrics fm = rgbaValues->fontMetrics();
        int width = fm.width("0.00000 0.00000 0.00000");
        rgbaValues->setMinimumWidth(width);
    }

    color = new QLabel(this);
    color->setFixedSize(20, 20);

    hvl_lastOption = new QLabel(this);
    {
        QFontMetrics fm = hvl_lastOption->fontMetrics();
        int width = fm.width("H:000 S:0.00 V:0.00 L:0.00000");
        hvl_lastOption->setMinimumWidth(width);
    }

    layout->addWidget(descriptionLabel);
    layout->addWidget(imageFormat);
    layout->addWidget(resolution);
    layout->addWidget(coordDispWindow);
    layout->addWidget(_fpsLabel);
    layout->addWidget(coordMouse);
    layout->addWidget(rgbaValues);
    layout->addWidget(color);
    layout->addWidget(hvl_lastOption);

}

QSize
InfoViewerWidget::sizeHint() const
{
    return QWidget::sizeHint();
}

QSize
InfoViewerWidget::minimumSizeHint() const
{
    return QWidget::minimumSizeHint();
}

void
InfoViewerWidget::setFps(double actualFps,
                         double desiredFps)
{
    QString colorStr("green");

    const QFont& font = _fpsLabel->font();

    if ( ( actualFps < (desiredFps -  desiredFps / 10.f) ) && ( actualFps > (desiredFps / 2.f) ) ) {
        colorStr = QString("orange");
    } else if ( actualFps < (desiredFps / 2.f) ) {
        colorStr = QString("red");
    }
    QString str = QString("%1 fps")
    .arg( QString::number(actualFps,'f',1) )
    .arg(font.family())
    .arg(font.pixelSize());

    _fpsLabel->setText(str);
    if ( !_fpsLabel->isVisible() ) {
        _fpsLabel->show();
    }
}

void
InfoViewerWidget::hideFps()
{
    if ( _fpsLabel->isVisible() ) {
        _fpsLabel->hide();
    }
}

bool
InfoViewerWidget::colorAndMouseVisible()
{
    return coordMouse->isVisible();
}

void
InfoViewerWidget::showColorAndMouseInfo()
{
    coordMouse->show();
    hvl_lastOption->show();
    rgbaValues->show();
    color->show();
}

void
InfoViewerWidget::hideColorAndMouseInfo()
{
    coordMouse->hide();
    hvl_lastOption->hide();
    rgbaValues->hide();
    color->hide();
}

InfoViewerWidget::~InfoViewerWidget()
{
}

void
InfoViewerWidget::setColor(float r,
                           float g,
                           float b,
                           float a)
{
    QString values;
    const QFont& font = rgbaValues->font();
    //values = QString("%1 %2 %3 %4")
    // the following three colors have an equal luminance (=0.4), which makes the text easier to read.
    switch (_comp) {
    case Natron::eImageComponentNone:
        values = QString();
        break;
    case Natron::eImageComponentAlpha:
        values = QString("%1")
            .arg(a,0,'f',5).arg(font.family()).arg(font.pixelSize());
        break;
    case Natron::eImageComponentRGB:
        values = QString("%1  "
                           "%2  "
                           "%3")
                   .arg(r,0,'f',5)
                   .arg(g,0,'f',5)
                   .arg(b,0,'f',5)
                   .arg(font.family())
                   .arg(font.pixelSize());
        break;
    case Natron::eImageComponentRGBA:
        values = QString("%1  "
                           "%2  "
                           "%3  "
                           "%4")
                   .arg(r,0,'f',5)
                   .arg(g,0,'f',5)
                   .arg(b,0,'f',5)
                   .arg(a,0,'f',5)
                   .arg(font.family())
                   .arg(font.pixelSize());
        break;
    }
    rgbaValues->setText(values);
    rgbaValues->repaint();
    float h,s,v,l;
    // Nuke's HSV display is based on sRGB, an L is Rec.709.
    // see http://forums.thefoundry.co.uk/phpBB2/viewtopic.php?t=2283
    double srgb_r = Color::to_func_srgb(r);
    double srgb_g = Color::to_func_srgb(g);
    double srgb_b = Color::to_func_srgb(b);
    QColor col;
    col.setRgbF( Natron::clamp(srgb_r), Natron::clamp(srgb_g), Natron::clamp(srgb_b) );
    QPixmap pix(15,15);
    pix.fill(col);
    color->setPixmap(pix);
    color->repaint();

    const QFont &hsvFont = hvl_lastOption->font();

    Color::rgb_to_hsv(srgb_r,srgb_g,srgb_b,&h,&s,&v);
    l = 0.2125 * r + 0.7154 * g + 0.0721 * b; // L according to Rec.709
    QString hsvlValues;
    hsvlValues = QString("H:%1 S:%2 V:%3  L:%4")
                 .arg(h,0,'f',0)
                 .arg(s,0,'f',2)
                 .arg(v,0,'f',2)
                 .arg(l,0,'f',5)
                 .arg(hsvFont.family())
                 .arg(hsvFont.pixelSize());

    hvl_lastOption->setText(hsvlValues);
    hvl_lastOption->repaint();
} // setColor

void
InfoViewerWidget::setMousePos(QPoint p)
{
    QString coord;
    const QFont& font = coordMouse->font();
    coord = QString("x=%1 y=%2")
            .arg( p.x() )
            .arg( p.y() )
            .arg(font.family())
            .arg(font.pixelSize());
    coordMouse->setText(coord);
}

void
InfoViewerWidget::setResolution(const Format & f)
{
    assert( QThread::currentThread() == qApp->thread() );
    format = f;

    const QFont& font = resolution->font();
    if ( format.getName() == std::string("") ) {
        QString reso;
        reso = QString("%1x%2")
        .arg( std::ceil(format.width()) )
        .arg( std::ceil(format.height()) )
        .arg(font.family())
        .arg(font.pixelSize());
        resolution->setText(reso);
    } else {
        QString reso = QString("")
        .arg(font.family())
        .arg(font.pixelSize());
        reso.append( format.getName().c_str() );
      //  reso.append("\t");
        reso.append("");
        resolution->setText(reso);
    }
}

void
InfoViewerWidget::setDataWindow(const RectD & r)
{
    QString bbox;
    const QFont& font = coordDispWindow->font();
    bbox = QString("RoD: %1 %2 %3 %4")
           .arg( std::ceil( r.left() ) )
           .arg( std::ceil( r.bottom() ) )
           .arg( std::floor( r.right() ) )
           .arg( std::floor( r.top() ) )
           .arg(font.family())
           .arg(font.pixelSize());

    coordDispWindow->setText(bbox);
}

void
InfoViewerWidget::setImageFormat(Natron::ImageComponentsEnum comp,
                                 Natron::ImageBitDepthEnum depth)
{

    const QFont& font = imageFormat->font();
    QString text = QString("")
    .arg(font.family())
    .arg(font.pixelSize());
    QString format(Natron::Image::getFormatString(comp, depth).c_str());
    text.append(format);
    text.append("");
    imageFormat->setText(text);
    _comp = comp;
}

void
InfoViewerWidget::paintEvent(QPaintEvent* e)
{
    QWidget::paintEvent(e);
}

<|endoftext|>


<commit_before>/*
   fuse-demo: a FUSE filesystem demo of fskit
   Copyright (C) 2014  Jude Nelson

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "fuse-demo.h"

int main( int argc, char** argv ) {

   int rc = 0;
   struct fskit_fuse_state state;

   // set up
   rc = fskit_fuse_init( &state, NULL );
   if( rc != 0 ) {
      fprintf(stderr, "fskit_fuse_init rc = %d\n", rc );
      exit(1);
   }

   // run
   rc = fskit_fuse_main( &state, argc, argv );

   // shutdown
   fskit_fuse_shutdown( &state, NULL );

   return rc;
}
<commit_msg>Make the FUSE demo store data persistently. To demonstrate the power of WSGI-style route matching combined with fskit's "batteries included" metadata-handling features, have the FUSE demo store all file data in a flat namespace named by inodes.  fskit will handle resolving paths to inodes.<commit_after>/*
   fuse-demo: a FUSE filesystem demo of fskit
   Copyright (C) 2014  Jude Nelson

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * This is a basic fskit-powered FUSE filesystem that stores data to disk.
 * Instead of storing data by path, it stores data by inode number.
 *
 * Usage:
 *    ./fuse-demo [fuse opts] storage_dir mountpoint_dir
 */

#include "fuse-demo.h"

// fskit file handle data
struct demo_fd {
   int fd;
};

// convert an inode to a 16-byte null-terminated string
int inode_to_string( uint64_t inode_num, char* buf ) {

   memset( buf, 0, 17 );
   sprintf( buf, "%016" PRIX64, inode_num );
   return 0;
}

// file create callback
// create the file $storage_dir/$inode
// keep the file descriptor in a demo_fd.
int create_cb( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, mode_t mode, void** inode_data, void** handle_data ) {

   char buf[17];
   char* path = NULL;
   char* storage_root = (char*)fskit_core_get_user_data( core );
   int rc = 0;
   struct demo_fd* dfd = (struct demo_fd*)calloc( sizeof(struct demo_fd), 1 );

   inode_to_string( fent->file_id, buf );
   path = fskit_fullpath( storage_root, buf, NULL );

   dfd->fd = creat( path, mode );
   rc = -errno;

   free( path );

   if( dfd->fd >= 0 ) {
      *handle_data = (void*)dfd;
      return 0;
   }
   else {
      free( dfd );
      return rc;
   }
}

// file open callback
// open the file $storage_dir/$inode
// keep the file descriptor in a demo_fd
int open_cb( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, int flags, void** handle_data ) {

   char buf[17];
   char* path = NULL;
   char* storage_root = (char*)fskit_core_get_user_data( core );
   int rc = 0;
   uint64_t inode_num = fskit_entry_get_file_id( fent );
   struct demo_fd* dfd = (struct demo_fd*)calloc( sizeof(struct demo_fd), 1 );

   inode_to_string( inode_num, buf );
   path = fskit_fullpath( storage_root, buf, NULL );

   dfd->fd = open( path, flags );
   rc = -errno;

   free( path );

   if( dfd->fd >= 0 ) {
      *handle_data = (void*)dfd;
      return 0;
   }
   else {
      free( dfd );
      return rc;
   }
}

// file close callback
// close the file $storage_dir/$inode
// free the demo_fd
int close_cb( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, void* handle_data ) {

   struct demo_fd* dfd = (struct demo_fd*)handle_data;
   int rc = 0;

   close( dfd->fd );
   rc = -errno;
   free( dfd );
   return rc;
}

// file read callback
// extract the actual file descriptor and call read(2)
int read_cb( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, char* buf, size_t buflen, off_t offset, void* handle_data ) {

   struct demo_fd* dfd = (struct demo_fd*)handle_data;
   lseek( dfd->fd, offset, SEEK_SET );

   return read( dfd->fd, buf, buflen );
}

// file write callback
// extract the actual file descriptor and call write(2)
int write_cb( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, char* buf, size_t buflen, off_t offset, void* handle_data ) {

   struct demo_fd* dfd = (struct demo_fd*)handle_data;
   lseek( dfd->fd, offset, SEEK_SET );

   return write( dfd->fd, buf, buflen );
}

// file unlink callback
// unlink $storage_dir/$inode
int detach_cb( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, void* inode_data ) {

   char buf[17];
   char* path = NULL;
   int rc = 0;
   char* storage_root = (char*)fskit_core_get_user_data( core );
   uint64_t inode_num = fskit_entry_get_file_id( fent );

   inode_to_string( inode_num, buf );
   path = fskit_fullpath( storage_root, buf, NULL );

   unlink( path );
   rc = -errno;

   free( path );
   return rc;
}

void usage( char const* progname ) {
   fprintf(stderr, "Usage: %s [FUSE options] STORAGE MOUNTPOINT\n", progname);
}

int main( int argc, char** argv ) {

   int rc = 0;
   struct fskit_fuse_state state;
   struct fskit_core* core = NULL;
   char* storage_dir = NULL;

   if( argc < 3 ) {
      usage( argv[0] );
      exit(1);
   }

   storage_dir = argv[ argc - 2 ];
   argv[ argc - 2 ] = argv[ argc - 1 ];
   argv[ argc - 1 ] = NULL;
   argc--;

   // set up
   rc = fskit_fuse_init( &state, storage_dir );
   if( rc != 0 ) {
      fprintf(stderr, "fskit_fuse_init rc = %d\n", rc );
      exit(1);
   }

   core = fskit_fuse_get_core( &state );

   // add handlers.  reads and writes must happen sequentially, since we seek and then perform I/O
   // NOTE: FSKIT_ROUTE_ANY matches any path, and is a macro for the regex "/([^/]+[/]*)+"
   fskit_route_create( core, FSKIT_ROUTE_ANY, create_cb, FSKIT_CONCURRENT );
   fskit_route_open(   core, FSKIT_ROUTE_ANY, open_cb,   FSKIT_CONCURRENT );
   fskit_route_read(   core, FSKIT_ROUTE_ANY, read_cb,   FSKIT_SEQUENTIAL );
   fskit_route_write(  core, FSKIT_ROUTE_ANY, write_cb,  FSKIT_SEQUENTIAL );
   fskit_route_close(  core, FSKIT_ROUTE_ANY, close_cb,  FSKIT_CONCURRENT );
   fskit_route_detach( core, FSKIT_ROUTE_ANY, detach_cb, FSKIT_CONCURRENT );

   // set the root to be owned by the effective UID and GID of user
   fskit_chown( core, "/", 0, 0, geteuid(), getegid() );

   // run
   rc = fskit_fuse_main( &state, argc, argv );

   // shutdown
   fskit_fuse_shutdown( &state, NULL );

   return rc;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <math.h>
#include <string.h>
#include <vector>
#include "mex.h"

#include <nix.hpp>

#include "handle.h"
#include "arguments.h"
#include "struct.h"
#include "nix2mx.h"

#include "nixfile.h"
#include "nixsection.h"
#include "nixblock.h"
#include "nixdataarray.h"
#include "nixsource.h"
#include "nixfeature.h"
#include "nixtag.h"
#include "nixmultitag.h"

#include <utils/glue.h>

#include <mutex>

// *** functions ***

static void entity_destroy(const extractor &input, infusor &output)
{
    handle h = input.hdl(1);
    h.destroy();
}

static void entity_updated_at(const extractor &input, infusor &output)
{
    const handle::entity *curr = input.hdl(1).the_entity();
    time_t uat = curr->updated_at();
    uint64_t the_time = static_cast<uint64_t>(uat);
    output.set(0, the_time);
}

// *** ***

typedef void(*fn_t)(const extractor &input, infusor &output);

struct fendpoint {

    fendpoint(std::string name, fn_t fn) : name(name), fn(fn) {}

    std::string name;
    fn_t fn;
};

const std::vector<fendpoint> funcs = {
    // File
    { "File::listBlocks", nixfile::list_blocks },
    { "File::listSections", nixfile::list_sections },
    { "File::createBlock", nixfile::create_block },
    { "File::createSection", nixfile::create_section },

    // Block
    { "Block::describe", nixblock::describe },
    { "Block::listDataArrays", nixblock::list_data_arrays },
    { "Block::listSources", nixblock::list_sources },
    { "Block::listTags", nixblock::list_tags },
    { "Block::listMultiTags", nixblock::list_multi_tags },
    { "Block::createDataArray", nixblock::create_data_array },

    // Data Array
    { "DataArray::describe", nixdataarray::describe },
    { "DataArray::readAll", nixdataarray::read_all },
    { "DataArray::writeAll", nixdataarray::write_all },

    // Tag
    { "Tag::describe", nixtag::describe },
    { "Tag::listReferences", nixtag::list_references_array },
    { "Tag::listFeatures", nixtag::list_features },
    { "Tag::listSources", nixtag::list_sources },
    { "Tag::retrieveData", nixtag::retrieve_data },
    { "Tag::featureRetrieveData", nixtag::retrieve_feature_data },

    // Multi Tag
    { "MultiTag::describe", nixmultitag::describe },
    { "MultiTag::listReferences", nixmultitag::list_references_array },
    { "MultiTag::listFeatures", nixmultitag::list_features },
    { "MultiTag::listSources", nixmultitag::list_sources },
    { "MultiTag::retrieveData", nixmultitag::retrieve_data },
    { "MultiTag::featureRetrieveData", nixmultitag::retrieve_feature_data },

    // Source
    { "Source::describe", nixsource::describe },
    { "Source::listSources", nixsource::list_sources },

    // Feature
    { "Feature::describe", nixfeature::describe },
    { "Feature::linkType", nixfeature::link_type },

    // Section
    { "Section::describe", nixsection::describe },
    { "Section::listSections", nixsection::list_sections },
    { "Section::listProperties", nixsection::list_properties }
};

//glue "globals"
std::once_flag init_flag;
static glue::registry *methods = nullptr;

static void on_exit() {
#ifdef DEBUG_GLUE
    mexPrintf("[GLUE] deleting handlers!\n");
#endif

    delete methods;
}

#define GETTER(type, class, name) static_cast<type(class::*)()const>(&class::name)
#define GETBYSTR(type, class, name) static_cast<type(class::*)(const std::string &)const>(&class::name)
#define GETCONTENT(type, class, name) static_cast<type(class::*)()const>(&class::name)
#define GETSOURCES(base__) static_cast<std::vector<nix::Source>(nix::base::EntityWithSources<nix::base::base__>::*)(std::function<bool(const nix::Source &)>)const>(&nix::base::EntityWithSources<nix::base::base__>::sources)
//required to open nix::Section from DataArray, normal GETCONTENT leads to a compiler error with Visual Studio 12
#define GETMETADATA(base__) static_cast<nix::Section(nix::base::EntityWithMetadata<nix::base::base__>::*)()const>(&nix::base::EntityWithMetadata<nix::base::base__>::metadata)
#define REMOVER(type, class, name) static_cast<bool(class::*)(const std::string&)>(&class::name)

// main entry point
void mexFunction(int            nlhs,
    mxArray       *lhs[],
    int            nrhs,
    const mxArray *rhs[])
{
    extractor input(rhs, nrhs);
    infusor   output(lhs, nlhs);

    std::string cmd = input.str(0);

    //mexPrintf("[F] %s\n", cmd.c_str());

    std::call_once(init_flag, []() {
        using namespace glue;

#ifdef DEBUG_GLUE
        mexPrintf("[GLUE] Registering classdefs...\n");
#endif

        methods = new registry{};

        methods->add("Entity::destroy", entity_destroy);
        methods->add("Entity::updatedAt", entity_updated_at);

        classdef<nix::File>("File", methods)
            .desc(&nixfile::describe)
            .add("open", nixfile::open)
            .reg("blocks", GETTER(std::vector<nix::Block>, nix::File, blocks))
            .reg("sections", GETTER(std::vector<nix::Section>, nix::File, sections))
            .reg("deleteBlock", REMOVER(nix::Block, nix::File, deleteBlock))
            .reg("deleteSection", REMOVER(nix::Section, nix::File, deleteSection))
            .reg("openBlock", GETBYSTR(nix::Block, nix::File, getBlock))
            .reg("openSection", GETBYSTR(nix::Section, nix::File, getSection));

        classdef<nix::Block>("Block", methods)
            .reg("dataArrays", &nix::Block::dataArrays)
            .reg("createSource", &nix::Block::createSource)
            //.reg("createDataArray", static_cast<nix::DataArray(nix::Block::*)(const std::string &, const std::string &, nix::DataType, const nix::NDSize &)>(&nix::Block::createDataArray))
            .reg("createTag", &nix::Block::createTag)
            .reg("createMultiTag", &nix::Block::createMultiTag)
            .reg("sources", &nix::Block::sources)
            .reg("tags", &nix::Block::tags)
            .reg("multiTags", &nix::Block::multiTags)
            .reg("hasTag", GETBYSTR(bool, nix::Block, hasTag))
            .reg("hasMultiTag", GETBYSTR(bool, nix::Block, hasMultiTag))
            .reg("openDataArray", GETBYSTR(nix::DataArray, nix::Block, getDataArray))
            .reg("openSource", GETBYSTR(nix::Source, nix::Block, getSource))
            .reg("openTag", GETBYSTR(nix::Tag, nix::Block, getTag))
            .reg("openMultiTag", GETBYSTR(nix::MultiTag, nix::Block, getMultiTag))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::Block, metadata));

        classdef<nix::DataArray>("DataArray", methods)
            .reg("sources", GETSOURCES(IDataArray))
            .reg("openMetadataSection", GETMETADATA(IDataArray));

        classdef<nix::Source>("Source", methods)
            .reg("sources", &nix::Source::sources)
            .reg("openSource", GETBYSTR(nix::Source, nix::Source, getSource))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::Source, metadata));

        classdef<nix::Tag>("Tag", methods)
            .reg("references", GETTER(std::vector<nix::DataArray>, nix::Tag, references))
            .reg("features", &nix::Tag::features)
            .reg("sources", GETSOURCES(ITag))
            .reg("openReferenceDataArray", GETBYSTR(nix::DataArray, nix::Tag, getReference))
            .reg("openFeature", GETBYSTR(nix::Feature, nix::Tag, getFeature))
            .reg("openSource", GETBYSTR(nix::Source, nix::Tag, getSource))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::Tag, metadata));

        classdef<nix::MultiTag>("MultiTag", methods)
            .reg("references", GETTER(std::vector<nix::DataArray>, nix::MultiTag, references))
            .reg("features", &nix::MultiTag::features)
            .reg("sources", GETSOURCES(IMultiTag))
            .reg("hasPositions", GETCONTENT(bool, nix::MultiTag, hasPositions))
            .reg("openPositions", GETCONTENT(nix::DataArray, nix::MultiTag, positions))
            .reg("openExtents", GETCONTENT(nix::DataArray, nix::MultiTag, extents))
            .reg("openReferences", GETBYSTR(nix::DataArray, nix::MultiTag, getReference))
            .reg("openFeature", GETBYSTR(nix::Feature, nix::MultiTag, getFeature))
            .reg("openSource", GETBYSTR(nix::Source, nix::MultiTag, getSource))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::MultiTag, metadata));

        classdef<nix::Section>("Section", methods)
            .reg("sections", &nix::Section::sections)
            .reg("openSection", GETBYSTR(nix::Section, nix::Section, getSection))
            .reg("hasProperty", GETBYSTR(bool, nix::Section, hasProperty))
            .reg("hasSection", GETBYSTR(bool, nix::Section, hasSection))
            .reg("link", GETCONTENT(nix::Section, nix::Section, link))
            .reg("parent", GETCONTENT(nix::Section, nix::Section, parent));

        classdef<nix::Feature>("Feature", methods)
            .reg("openData", GETCONTENT(nix::DataArray, nix::Feature, data));

        mexAtExit(on_exit);
    });

    bool processed = false;

    try {
        processed = methods->dispatch(cmd, input, output);

#ifdef DEBUG_GLUE
        if (processed) {
            mexPrintf("[GLUE] %s: processed by glue.\n", cmd.c_str());
        }
#endif

        for (const auto &fn : funcs) {

            if (processed) {
                break;
            }

            if (fn.name == cmd) {
                fn.fn(input, output);
                processed = true;
            }
        }

    }
    catch (const std::invalid_argument &e) {
        mexErrMsgIdAndTxt("nix:arg:inval", e.what());
    }
    catch (const std::exception &e) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", e.what());
    }
    catch (...) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", "unkown exception");
    }

    if (!processed) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", "Unkown command");
    }
}

<commit_msg>moved array creation to new style<commit_after>#include <iostream>
#include <math.h>
#include <string.h>
#include <vector>
#include "mex.h"

#include <nix.hpp>

#include "handle.h"
#include "arguments.h"
#include "struct.h"
#include "nix2mx.h"

#include "nixfile.h"
#include "nixsection.h"
#include "nixblock.h"
#include "nixdataarray.h"
#include "nixsource.h"
#include "nixfeature.h"
#include "nixtag.h"
#include "nixmultitag.h"

#include <utils/glue.h>

#include <mutex>

// *** functions ***

static void entity_destroy(const extractor &input, infusor &output)
{
    handle h = input.hdl(1);
    h.destroy();
}

static void entity_updated_at(const extractor &input, infusor &output)
{
    const handle::entity *curr = input.hdl(1).the_entity();
    time_t uat = curr->updated_at();
    uint64_t the_time = static_cast<uint64_t>(uat);
    output.set(0, the_time);
}

// *** ***

typedef void(*fn_t)(const extractor &input, infusor &output);

struct fendpoint {

    fendpoint(std::string name, fn_t fn) : name(name), fn(fn) {}

    std::string name;
    fn_t fn;
};

const std::vector<fendpoint> funcs = {
    // File
    { "File::listBlocks", nixfile::list_blocks },
    { "File::listSections", nixfile::list_sections },
    { "File::createBlock", nixfile::create_block },
    { "File::createSection", nixfile::create_section },

    // Block
    { "Block::describe", nixblock::describe },
    { "Block::listDataArrays", nixblock::list_data_arrays },
    { "Block::listSources", nixblock::list_sources },
    { "Block::listTags", nixblock::list_tags },
    { "Block::listMultiTags", nixblock::list_multi_tags },

    // Data Array
    { "DataArray::describe", nixdataarray::describe },
    { "DataArray::readAll", nixdataarray::read_all },

    // Tag
    { "Tag::describe", nixtag::describe },
    { "Tag::listReferences", nixtag::list_references_array },
    { "Tag::listFeatures", nixtag::list_features },
    { "Tag::listSources", nixtag::list_sources },
    { "Tag::retrieveData", nixtag::retrieve_data },
    { "Tag::featureRetrieveData", nixtag::retrieve_feature_data },

    // Multi Tag
    { "MultiTag::describe", nixmultitag::describe },
    { "MultiTag::listReferences", nixmultitag::list_references_array },
    { "MultiTag::listFeatures", nixmultitag::list_features },
    { "MultiTag::listSources", nixmultitag::list_sources },
    { "MultiTag::retrieveData", nixmultitag::retrieve_data },
    { "MultiTag::featureRetrieveData", nixmultitag::retrieve_feature_data },

    // Source
    { "Source::describe", nixsource::describe },
    { "Source::listSources", nixsource::list_sources },

    // Feature
    { "Feature::describe", nixfeature::describe },
    { "Feature::linkType", nixfeature::link_type },

    // Section
    { "Section::describe", nixsection::describe },
    { "Section::listSections", nixsection::list_sections },
    { "Section::listProperties", nixsection::list_properties }
};

//glue "globals"
std::once_flag init_flag;
static glue::registry *methods = nullptr;

static void on_exit() {
#ifdef DEBUG_GLUE
    mexPrintf("[GLUE] deleting handlers!\n");
#endif

    delete methods;
}

#define GETTER(type, class, name) static_cast<type(class::*)()const>(&class::name)
#define GETBYSTR(type, class, name) static_cast<type(class::*)(const std::string &)const>(&class::name)
#define GETCONTENT(type, class, name) static_cast<type(class::*)()const>(&class::name)
#define GETSOURCES(base__) static_cast<std::vector<nix::Source>(nix::base::EntityWithSources<nix::base::base__>::*)(std::function<bool(const nix::Source &)>)const>(&nix::base::EntityWithSources<nix::base::base__>::sources)
//required to open nix::Section from DataArray, normal GETCONTENT leads to a compiler error with Visual Studio 12
#define GETMETADATA(base__) static_cast<nix::Section(nix::base::EntityWithMetadata<nix::base::base__>::*)()const>(&nix::base::EntityWithMetadata<nix::base::base__>::metadata)
#define REMOVER(type, class, name) static_cast<bool(class::*)(const std::string&)>(&class::name)

// main entry point
void mexFunction(int            nlhs,
    mxArray       *lhs[],
    int            nrhs,
    const mxArray *rhs[])
{
    extractor input(rhs, nrhs);
    infusor   output(lhs, nlhs);

    std::string cmd = input.str(0);

    //mexPrintf("[F] %s\n", cmd.c_str());

    std::call_once(init_flag, []() {
        using namespace glue;

#ifdef DEBUG_GLUE
        mexPrintf("[GLUE] Registering classdefs...\n");
#endif

        methods = new registry{};

        methods->add("Entity::destroy", entity_destroy);
        methods->add("Entity::updatedAt", entity_updated_at);

        classdef<nix::File>("File", methods)
            .desc(&nixfile::describe)
            .add("open", nixfile::open)
            .reg("blocks", GETTER(std::vector<nix::Block>, nix::File, blocks))
            .reg("sections", GETTER(std::vector<nix::Section>, nix::File, sections))
            .reg("deleteBlock", REMOVER(nix::Block, nix::File, deleteBlock))
            .reg("deleteSection", REMOVER(nix::Section, nix::File, deleteSection))
            .reg("openBlock", GETBYSTR(nix::Block, nix::File, getBlock))
            .reg("openSection", GETBYSTR(nix::Section, nix::File, getSection));

        classdef<nix::Block>("Block", methods)
            .reg("dataArrays", &nix::Block::dataArrays)
            .reg("createSource", &nix::Block::createSource)
            //.reg("createDataArray", static_cast<nix::DataArray(nix::Block::*)(const std::string &, const std::string &, nix::DataType, const nix::NDSize &)>(&nix::Block::createDataArray))
            .reg("createTag", &nix::Block::createTag)
            .reg("createMultiTag", &nix::Block::createMultiTag)
            .reg("sources", &nix::Block::sources)
            .reg("tags", &nix::Block::tags)
            .reg("multiTags", &nix::Block::multiTags)
            .reg("hasTag", GETBYSTR(bool, nix::Block, hasTag))
            .reg("hasMultiTag", GETBYSTR(bool, nix::Block, hasMultiTag))
            .reg("openDataArray", GETBYSTR(nix::DataArray, nix::Block, getDataArray))
            .reg("openSource", GETBYSTR(nix::Source, nix::Block, getSource))
            .reg("openTag", GETBYSTR(nix::Tag, nix::Block, getTag))
            .reg("openMultiTag", GETBYSTR(nix::MultiTag, nix::Block, getMultiTag))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::Block, metadata));
        methods->add("Block::createDataArray", nixblock::create_data_array);

        classdef<nix::DataArray>("DataArray", methods)
            .reg("sources", GETSOURCES(IDataArray))
            .reg("openMetadataSection", GETMETADATA(IDataArray));
        methods->add("DataArray::writeAll", nixdataarray::write_all);

        classdef<nix::Source>("Source", methods)
            .reg("sources", &nix::Source::sources)
            .reg("openSource", GETBYSTR(nix::Source, nix::Source, getSource))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::Source, metadata));

        classdef<nix::Tag>("Tag", methods)
            .reg("references", GETTER(std::vector<nix::DataArray>, nix::Tag, references))
            .reg("features", &nix::Tag::features)
            .reg("sources", GETSOURCES(ITag))
            .reg("openReferenceDataArray", GETBYSTR(nix::DataArray, nix::Tag, getReference))
            .reg("openFeature", GETBYSTR(nix::Feature, nix::Tag, getFeature))
            .reg("openSource", GETBYSTR(nix::Source, nix::Tag, getSource))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::Tag, metadata));

        classdef<nix::MultiTag>("MultiTag", methods)
            .reg("references", GETTER(std::vector<nix::DataArray>, nix::MultiTag, references))
            .reg("features", &nix::MultiTag::features)
            .reg("sources", GETSOURCES(IMultiTag))
            .reg("hasPositions", GETCONTENT(bool, nix::MultiTag, hasPositions))
            .reg("openPositions", GETCONTENT(nix::DataArray, nix::MultiTag, positions))
            .reg("openExtents", GETCONTENT(nix::DataArray, nix::MultiTag, extents))
            .reg("openReferences", GETBYSTR(nix::DataArray, nix::MultiTag, getReference))
            .reg("openFeature", GETBYSTR(nix::Feature, nix::MultiTag, getFeature))
            .reg("openSource", GETBYSTR(nix::Source, nix::MultiTag, getSource))
            .reg("openMetadataSection", GETCONTENT(nix::Section, nix::MultiTag, metadata));

        classdef<nix::Section>("Section", methods)
            .reg("sections", &nix::Section::sections)
            .reg("openSection", GETBYSTR(nix::Section, nix::Section, getSection))
            .reg("hasProperty", GETBYSTR(bool, nix::Section, hasProperty))
            .reg("hasSection", GETBYSTR(bool, nix::Section, hasSection))
            .reg("link", GETCONTENT(nix::Section, nix::Section, link))
            .reg("parent", GETCONTENT(nix::Section, nix::Section, parent));

        classdef<nix::Feature>("Feature", methods)
            .reg("openData", GETCONTENT(nix::DataArray, nix::Feature, data));

        mexAtExit(on_exit);
    });

    bool processed = false;

    try {
        processed = methods->dispatch(cmd, input, output);

#ifdef DEBUG_GLUE
        if (processed) {
            mexPrintf("[GLUE] %s: processed by glue.\n", cmd.c_str());
        }
#endif

        for (const auto &fn : funcs) {

            if (processed) {
                break;
            }

            if (fn.name == cmd) {
                fn.fn(input, output);
                processed = true;
            }
        }

    }
    catch (const std::invalid_argument &e) {
        mexErrMsgIdAndTxt("nix:arg:inval", e.what());
    }
    catch (const std::exception &e) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", e.what());
    }
    catch (...) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", "unkown exception");
    }

    if (!processed) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", "Unkown command");
    }
}

<|endoftext|>


<commit_before>// This file is part of the HörTech Open Master Hearing Aid (openMHA)
// Copyright © 2010 2011 2012 2013 2014 2015 2016 2018 2019 2020 HörTech gGmbH
//
// openMHA is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// openMHA 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 Affero General Public License, version 3 for more details.
//
// You should have received a copy of the GNU Affero General Public License,
// version 3 along with openMHA.  If not, see <http://www.gnu.org/licenses/>.

#include <time.h>
#include <pthread.h>
#include "mha_plugin.hh"
#include "mha_fifo.h"
#include <sndfile.h>
#include <sys/time.h>
#include <atomic>

class wavwriter_t {
public:
    wavwriter_t(bool active,const mhaconfig_t& cf,unsigned int fifosize,unsigned int minwrite,
                const std::string& prefix,bool use_date);
    ~wavwriter_t();
    void process(mha_wave_t*);
    void exit_request();
private:
    static void* write_thread(void* this_){((wavwriter_t*)this_)->write_thread();return NULL;};
    void write_thread();
    void create_soundfile(const std::string& prefix, bool use_date);
    std::atomic<bool> close_session;
    bool act_;
    mhaconfig_t cf_;
    SNDFILE* sf;
    mha_fifo_t<mha_real_t> fifo;
    unsigned int minw_;
    pthread_t writethread;
    float* data;
};

class wavrec_t : public MHAPlugin::plugin_t<wavwriter_t> {
public:
    mha_wave_t* process(mha_wave_t*);
    void prepare(mhaconfig_t& cf);
    void release();
    wavrec_t(const algo_comm_t& iac,const std::string&,const std::string&);
private:
    void start_new_session();
    MHAParser::bool_t record;
    MHAParser::int_t fifolen;
    MHAParser::int_t minwrite;
    MHAParser::string_t prefix;
    MHAParser::bool_t use_date;
    MHAEvents::patchbay_t<wavrec_t> patchbay;
};

wavrec_t::wavrec_t(const algo_comm_t& iac,const std::string&,const std::string& algo_name)
    : MHAPlugin::plugin_t<wavwriter_t>("wav file recorder",iac),
      record("Record session. Each write access with argument \"yes\" will start a\n"
             "new file with current time and date as a name.","no"),
      fifolen("Length of FIFO in samples","262144","[2,]"),
      minwrite("Minimal write length (must be less then fifolen)","65536","[1,]"),
      prefix("Path (including path delimiter) and file prefix",""),
      use_date("Use date and time (yes), or only prefix (no)","yes")
{
    // make the plug-in findable via "?listid"
    set_node_id(algo_name);

    insert_member(fifolen);
    insert_member(minwrite);
    insert_member(prefix);
    insert_member(use_date);
    insert_member(record);
    patchbay.connect(&record.writeaccess,this,&wavrec_t::start_new_session);
}

mha_wave_t* wavrec_t::process(mha_wave_t* s)
{
    poll_config()->process(s);
    return s;
}

void wavrec_t::prepare(mhaconfig_t& cf)
{
    start_new_session();
}

void wavrec_t::release()
{
    auto latest_cfg=peek_config();
    if(latest_cfg)
        latest_cfg->exit_request();
}

void wavrec_t::start_new_session()
{
    auto latest_cfg=peek_config();
    if(latest_cfg)
        latest_cfg->exit_request();
    push_config(new wavwriter_t(record.data,input_cfg(),fifolen.data,minwrite.data,prefix.data,use_date.data));
}

void wavwriter_t::create_soundfile(const std::string& prefix, bool use_date)
{
    std::string fname;
    if( use_date ){
        time_t tm(time(NULL));
#ifdef _WIN32
        fname = ctime(&tm);
#else
        char timestr[28];
        fname = ctime_r(&tm,timestr);
#endif
        fname.erase(fname.size()-1,1);
        MHAParser::strreplace(fname,":","-");
        MHAParser::strreplace(fname,"Mon "," ");
        MHAParser::strreplace(fname,"Tue "," ");
        MHAParser::strreplace(fname,"Wed "," ");
        MHAParser::strreplace(fname,"Thu "," ");
        MHAParser::strreplace(fname,"Fri "," ");
        MHAParser::strreplace(fname,"Sat "," ");
        MHAParser::strreplace(fname,"Sun "," ");
        MHAParser::strreplace(fname," ","_");
    }
    fname = prefix+fname+".wav";
    SF_INFO sfinfo;
    memset(&sfinfo,0,sizeof(sfinfo));
    sfinfo.samplerate = (int)cf_.srate;
    sfinfo.channels = cf_.channels;
    sfinfo.format = SF_FORMAT_WAV|SF_FORMAT_FLOAT|SF_ENDIAN_FILE;
    sf = sf_open(fname.c_str(),SFM_WRITE,&sfinfo);
    if( !sf )
        throw MHA_Error(__FILE__,__LINE__,"Unable to create sound file %s: %s",fname.c_str(),sf_strerror(sf));
}

wavwriter_t::wavwriter_t(bool active,const mhaconfig_t& cf,unsigned int fifosize,unsigned int minwrite,
                         const std::string& prefix, bool use_date)
    : close_session(false),
      act_(active),
      cf_(cf),
      sf(NULL),
      fifo(fifosize),
      minw_(minwrite),
      data(new float[fifosize])
{
    if(minw_ >= fifosize )
        throw MHA_Error(__FILE__,__LINE__,"minwrite must be less then fifosize (minwrite: %u, fifosize: %u)",minw_,fifosize);
    if( (cf_.channels == 0) || (cf_.srate==0) )
        act_ = false;
    if( act_ ){
        create_soundfile(prefix, use_date);
        pthread_create(&writethread,NULL,&wavwriter_t::write_thread,this);
    }
}

wavwriter_t::~wavwriter_t()
{
    delete [] data;
}

void wavwriter_t::process(mha_wave_t* s)
{
    if( act_ )
        fifo.write(s->buf,std::min(fifo.get_available_space(),size(s)));
}

void wavwriter_t::exit_request(){
    if(!close_session.load()){
        close_session.store(true);
        if( act_ ){
            pthread_join(writethread,NULL);
        }
        if( sf ){
            sf_close(sf);
            sf=nullptr;
        }
    }
    return;
}

void wavwriter_t::write_thread()
{
    while(!close_session.load()){
        mha_msleep(1);
        if( sf && (fifo.get_fill_count() > minw_) ){
            unsigned int frames = fifo.get_fill_count()/cf_.channels;
            fifo.read(data,frames*cf_.channels);
            sf_writef_float(sf,data,frames);
        }
    }
    if( sf && fifo.get_fill_count() ){
        unsigned int frames = fifo.get_fill_count()/cf_.channels;
        fifo.read(data,frames*cf_.channels);
        sf_writef_float(sf,data,frames);
    }
}

MHAPLUGIN_CALLBACKS(wavrec,wavrec_t,wave,wave)
MHAPLUGIN_DOCUMENTATION\
(wavrec,
 "data-export disk-files",
 "")

/*
 * Local Variables:
 * compile-command: "make"
 * c-basic-offset: 4
 * End:
 */
<commit_msg>Fix wavrec documentation<commit_after>// This file is part of the HörTech Open Master Hearing Aid (openMHA)
// Copyright © 2010 2011 2012 2013 2014 2015 2016 2018 2019 2020 HörTech gGmbH
//
// openMHA is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// openMHA 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 Affero General Public License, version 3 for more details.
//
// You should have received a copy of the GNU Affero General Public License,
// version 3 along with openMHA.  If not, see <http://www.gnu.org/licenses/>.

#include <time.h>
#include <pthread.h>
#include "mha_plugin.hh"
#include "mha_fifo.h"
#include <sndfile.h>
#include <sys/time.h>
#include <atomic>

class wavwriter_t {
public:
    wavwriter_t(bool active,const mhaconfig_t& cf,unsigned int fifosize,unsigned int minwrite,
                const std::string& prefix,bool use_date);
    ~wavwriter_t();
    void process(mha_wave_t*);
    void exit_request();
private:
    static void* write_thread(void* this_){((wavwriter_t*)this_)->write_thread();return NULL;};
    void write_thread();
    void create_soundfile(const std::string& prefix, bool use_date);
    std::atomic<bool> close_session;
    bool act_;
    mhaconfig_t cf_;
    SNDFILE* sf;
    mha_fifo_t<mha_real_t> fifo;
    unsigned int minw_;
    pthread_t writethread;
    float* data;
};

class wavrec_t : public MHAPlugin::plugin_t<wavwriter_t> {
public:
    mha_wave_t* process(mha_wave_t*);
    void prepare(mhaconfig_t& cf);
    void release();
    wavrec_t(const algo_comm_t& iac,const std::string&,const std::string&);
private:
    void start_new_session();
    MHAParser::bool_t record;
    MHAParser::int_t fifolen;
    MHAParser::int_t minwrite;
    MHAParser::string_t prefix;
    MHAParser::bool_t use_date;
    MHAEvents::patchbay_t<wavrec_t> patchbay;
};

wavrec_t::wavrec_t(const algo_comm_t& iac,const std::string&,const std::string& algo_name)
    : MHAPlugin::plugin_t<wavwriter_t>("wav file recorder",iac),
      record("Record session. Each write access with argument \"yes\" will start a\n"
             "new file with current time and date as a name.","no"),
      fifolen("Length of FIFO in samples","262144","[2,]"),
      minwrite("Minimal write length (must be less then fifolen)","65536","[1,]"),
      prefix("Path (including path delimiter) and file prefix",""),
      use_date("Use date and time (yes), or only prefix (no)","yes")
{
    // make the plug-in findable via "?listid"
    set_node_id(algo_name);

    insert_member(fifolen);
    insert_member(minwrite);
    insert_member(prefix);
    insert_member(use_date);
    insert_member(record);
    patchbay.connect(&record.writeaccess,this,&wavrec_t::start_new_session);
}

mha_wave_t* wavrec_t::process(mha_wave_t* s)
{
    poll_config()->process(s);
    return s;
}

void wavrec_t::prepare(mhaconfig_t& cf)
{
    start_new_session();
}

void wavrec_t::release()
{
    auto latest_cfg=peek_config();
    if(latest_cfg)
        latest_cfg->exit_request();
}

void wavrec_t::start_new_session()
{
    auto latest_cfg=peek_config();
    if(latest_cfg)
        latest_cfg->exit_request();
    push_config(new wavwriter_t(record.data,input_cfg(),fifolen.data,minwrite.data,prefix.data,use_date.data));
}

void wavwriter_t::create_soundfile(const std::string& prefix, bool use_date)
{
    std::string fname;
    if( use_date ){
        time_t tm(time(NULL));
#ifdef _WIN32
        fname = ctime(&tm);
#else
        char timestr[28];
        fname = ctime_r(&tm,timestr);
#endif
        fname.erase(fname.size()-1,1);
        MHAParser::strreplace(fname,":","-");
        MHAParser::strreplace(fname,"Mon "," ");
        MHAParser::strreplace(fname,"Tue "," ");
        MHAParser::strreplace(fname,"Wed "," ");
        MHAParser::strreplace(fname,"Thu "," ");
        MHAParser::strreplace(fname,"Fri "," ");
        MHAParser::strreplace(fname,"Sat "," ");
        MHAParser::strreplace(fname,"Sun "," ");
        MHAParser::strreplace(fname," ","_");
    }
    fname = prefix+fname+".wav";
    SF_INFO sfinfo;
    memset(&sfinfo,0,sizeof(sfinfo));
    sfinfo.samplerate = (int)cf_.srate;
    sfinfo.channels = cf_.channels;
    sfinfo.format = SF_FORMAT_WAV|SF_FORMAT_FLOAT|SF_ENDIAN_FILE;
    sf = sf_open(fname.c_str(),SFM_WRITE,&sfinfo);
    if( !sf )
        throw MHA_Error(__FILE__,__LINE__,"Unable to create sound file %s: %s",fname.c_str(),sf_strerror(sf));
}

wavwriter_t::wavwriter_t(bool active,const mhaconfig_t& cf,unsigned int fifosize,unsigned int minwrite,
                         const std::string& prefix, bool use_date)
    : close_session(false),
      act_(active),
      cf_(cf),
      sf(NULL),
      fifo(fifosize),
      minw_(minwrite),
      data(new float[fifosize])
{
    if(minw_ >= fifosize )
        throw MHA_Error(__FILE__,__LINE__,"minwrite must be less then fifosize (minwrite: %u, fifosize: %u)",minw_,fifosize);
    if( (cf_.channels == 0) || (cf_.srate==0) )
        act_ = false;
    if( act_ ){
        create_soundfile(prefix, use_date);
        pthread_create(&writethread,NULL,&wavwriter_t::write_thread,this);
    }
}

wavwriter_t::~wavwriter_t()
{
    delete [] data;
}

void wavwriter_t::process(mha_wave_t* s)
{
    if( act_ )
        fifo.write(s->buf,std::min(fifo.get_available_space(),size(s)));
}

void wavwriter_t::exit_request(){
    if(!close_session.load()){
        close_session.store(true);
        if( act_ ){
            pthread_join(writethread,NULL);
        }
        if( sf ){
            sf_close(sf);
            sf=nullptr;
        }
    }
    return;
}

void wavwriter_t::write_thread()
{
    while(!close_session.load()){
        mha_msleep(1);
        if( sf && (fifo.get_fill_count() > minw_) ){
            unsigned int frames = fifo.get_fill_count()/cf_.channels;
            fifo.read(data,frames*cf_.channels);
            sf_writef_float(sf,data,frames);
        }
    }
    if( sf && fifo.get_fill_count() ){
        unsigned int frames = fifo.get_fill_count()/cf_.channels;
        fifo.read(data,frames*cf_.channels);
        sf_writef_float(sf,data,frames);
    }
}

MHAPLUGIN_CALLBACKS(wavrec,wavrec_t,wave,wave)
MHAPLUGIN_DOCUMENTATION\
(wavrec,
 "data-export disk-files",
 "Wave file recorder plugin. This plugin writes the current audio signal to a wave file in a thread-safe manner."
 " A new wave file is opened every time the record variable is set to yes. The file is"
 " closed on any of \"cmd=release\", \"cmd=quit\" or \"record=no\". Note that \"cmd=stop\" does not"
 " close the wave file. After the the close command is given, it can take an unspecified, but usually small amount"
 " amount of time until the file is actually closed and ready for further processing. \n"
 " The name (and path) of the output file is chosen by the prefix configuration variable. By default the current"
 " date and time are appended to the file name, this behaviour can be controlled by the \"use\\_date\" variable.\n"
 "The \"fifolen\" and \"minwrite\" variables control the behaviour of the fifo buffer and should usually remain unchanged.")

/*
 * Local Variables:
 * compile-command: "make"
 * c-basic-offset: 4
 * End:
 */
<|endoftext|>


<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZART_BOOSTENV_DECL_H
#define MOZART_BOOSTENV_DECL_H

#include <mozart.hh>

#include <ctime>
#include <cstdio>
#include <cerrno>
#include <forward_list>

#include <boost/thread.hpp>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/random_generator.hpp>

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>

namespace mozart { namespace boostenv {

//////////////////
// BoostBasedVM //
//////////////////

class BoostBasedVM: public VirtualMachineEnvironment {
private:
  using BootLoader = std::function<bool(VM vm, const std::string& url,
                                        UnstableNode& result)>;

public:
  BoostBasedVM(size_t maxMemory);

  static BoostBasedVM& forVM(VM vm) {
    return static_cast<BoostBasedVM&>(vm->getEnvironment());
  }

// Configuration

public:
  const BootLoader& getBootLoader() {
    return _bootLoader;
  }

  void setBootLoader(const BootLoader& loader) {
    _bootLoader = loader;
  }

  void setApplicationURL(char const* url);

  void setApplicationArgs(int argc, char const* const* argv);

// Run and preemption

public:
  void run();
private:
  void onPreemptionTimerExpire(const boost::system::error_code& error);

// Time

  static std::int64_t getReferenceTime() {
    return ptimeToReferenceTime(
      boost::posix_time::microsec_clock::universal_time());
  }

  static boost::posix_time::ptime referenceTimeToPTime(std::int64_t time) {
    return epoch() + boost::posix_time::millisec(time);
  }

  static std::int64_t ptimeToReferenceTime(boost::posix_time::ptime time) {
    return (time - epoch()).total_milliseconds();
  }

  static boost::posix_time::ptime epoch() {
    using namespace boost::gregorian;
    return boost::posix_time::ptime(date(1970, Jan, 1));
  }

// UUID generation

public:
  UUID genUUID();
private:
  inline
  static std::uint64_t bytes2uint64(const std::uint8_t* bytes);

// BigInt

public:
  inline
  virtual UnstableNode newBigInt(VM vm, nativeint value);

// Management of nodes used by asynchronous operations for feedback

public:
  inline
  ProtectedNode allocAsyncIONode(StableNode* node);

  inline
  void releaseAsyncIONode(const ProtectedNode& node);

  inline
  ProtectedNode createAsyncIOFeedbackNode(UnstableNode& readOnly);

  template <class LT, class... Args>
  inline
  void bindAndReleaseAsyncIOFeedbackNode(const ProtectedNode& ref,
                                         LT&& label, Args&&... args);

  template <class LT, class... Args>
  inline
  void raiseAndReleaseAsyncIOFeedbackNode(const ProtectedNode& ref,
                                          LT&& label, Args&&... args);

// Notification from asynchronous work

public:
  inline
  void postVMEvent(std::function<void()> callback);

// Reference to the virtual machine
private:
  VirtualMachine virtualMachine;
public:
  const VM vm;

// Bootstrap
private:
  BootLoader _bootLoader;

// Number of asynchronous IO nodes - used for termination detection
private:
  size_t _asyncIONodeCount;

// Random number generation
public:
  typedef boost::random::mt19937 random_generator_t;
  random_generator_t random_generator;
private:
  boost::uuids::random_generator uuidGenerator;

// ASIO service
public:
  boost::asio::io_service io_service;

// Synchronization condition variable telling there is work to do in the VM
private:
  boost::condition_variable _conditionWorkToDoInVM;
  boost::mutex _conditionWorkToDoInVMMutex;

// Preemption and alarms
private:
  boost::asio::deadline_timer preemptionTimer;
  boost::asio::deadline_timer alarmTimer;

// IO-driven events that must work with the VM store
private:
  std::queue<std::function<void()> > _vmEventsCallbacks;
};

///////////////
// Utilities //
///////////////

template <typename T>
inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  nativeint errnum, T&& message);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function, int errnum);

inline
void MOZART_NORETURN raiseLastOSError(VM vm, const char* function);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  boost::system::error_code& ec);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  const boost::system::system_error& error);

} }

#endif // MOZART_BOOSTENV_DECL_H
<commit_msg>Remove virtual from BoostBasedVM::newBigInt, it should not be overridden.<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZART_BOOSTENV_DECL_H
#define MOZART_BOOSTENV_DECL_H

#include <mozart.hh>

#include <ctime>
#include <cstdio>
#include <cerrno>
#include <forward_list>

#include <boost/thread.hpp>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/random_generator.hpp>

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>

namespace mozart { namespace boostenv {

//////////////////
// BoostBasedVM //
//////////////////

class BoostBasedVM: public VirtualMachineEnvironment {
private:
  using BootLoader = std::function<bool(VM vm, const std::string& url,
                                        UnstableNode& result)>;

public:
  BoostBasedVM(size_t maxMemory);

  static BoostBasedVM& forVM(VM vm) {
    return static_cast<BoostBasedVM&>(vm->getEnvironment());
  }

// Configuration

public:
  const BootLoader& getBootLoader() {
    return _bootLoader;
  }

  void setBootLoader(const BootLoader& loader) {
    _bootLoader = loader;
  }

  void setApplicationURL(char const* url);

  void setApplicationArgs(int argc, char const* const* argv);

// Run and preemption

public:
  void run();
private:
  void onPreemptionTimerExpire(const boost::system::error_code& error);

// Time

  static std::int64_t getReferenceTime() {
    return ptimeToReferenceTime(
      boost::posix_time::microsec_clock::universal_time());
  }

  static boost::posix_time::ptime referenceTimeToPTime(std::int64_t time) {
    return epoch() + boost::posix_time::millisec(time);
  }

  static std::int64_t ptimeToReferenceTime(boost::posix_time::ptime time) {
    return (time - epoch()).total_milliseconds();
  }

  static boost::posix_time::ptime epoch() {
    using namespace boost::gregorian;
    return boost::posix_time::ptime(date(1970, Jan, 1));
  }

// UUID generation

public:
  UUID genUUID();
private:
  inline
  static std::uint64_t bytes2uint64(const std::uint8_t* bytes);

// BigInt

public:
  inline
  UnstableNode newBigInt(VM vm, nativeint value);

// Management of nodes used by asynchronous operations for feedback

public:
  inline
  ProtectedNode allocAsyncIONode(StableNode* node);

  inline
  void releaseAsyncIONode(const ProtectedNode& node);

  inline
  ProtectedNode createAsyncIOFeedbackNode(UnstableNode& readOnly);

  template <class LT, class... Args>
  inline
  void bindAndReleaseAsyncIOFeedbackNode(const ProtectedNode& ref,
                                         LT&& label, Args&&... args);

  template <class LT, class... Args>
  inline
  void raiseAndReleaseAsyncIOFeedbackNode(const ProtectedNode& ref,
                                          LT&& label, Args&&... args);

// Notification from asynchronous work

public:
  inline
  void postVMEvent(std::function<void()> callback);

// Reference to the virtual machine
private:
  VirtualMachine virtualMachine;
public:
  const VM vm;

// Bootstrap
private:
  BootLoader _bootLoader;

// Number of asynchronous IO nodes - used for termination detection
private:
  size_t _asyncIONodeCount;

// Random number generation
public:
  typedef boost::random::mt19937 random_generator_t;
  random_generator_t random_generator;
private:
  boost::uuids::random_generator uuidGenerator;

// ASIO service
public:
  boost::asio::io_service io_service;

// Synchronization condition variable telling there is work to do in the VM
private:
  boost::condition_variable _conditionWorkToDoInVM;
  boost::mutex _conditionWorkToDoInVMMutex;

// Preemption and alarms
private:
  boost::asio::deadline_timer preemptionTimer;
  boost::asio::deadline_timer alarmTimer;

// IO-driven events that must work with the VM store
private:
  std::queue<std::function<void()> > _vmEventsCallbacks;
};

///////////////
// Utilities //
///////////////

template <typename T>
inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  nativeint errnum, T&& message);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function, int errnum);

inline
void MOZART_NORETURN raiseLastOSError(VM vm, const char* function);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  boost::system::error_code& ec);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  const boost::system::system_error& error);

} }

#endif // MOZART_BOOSTENV_DECL_H
<|endoftext|>


<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZART_BOOSTENV_DECL_H
#define MOZART_BOOSTENV_DECL_H

#include <mozart.hh>

#include <ctime>
#include <cstdio>
#include <cerrno>
#include <forward_list>
#include <mutex>

#include <boost/thread.hpp>

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include "boostvm-decl.hh"
#include "boostenvbigint-decl.hh"

namespace mozart { namespace boostenv {

//////////////////////
// BoostEnvironment //
//////////////////////

class BoostEnvironment: public VirtualMachineEnvironment {
private:
  using BootLoader = std::function<bool(VM vm, const std::string& url,
                                        UnstableNode& result)>;
  using VMStarter = std::function<bool(VM vm, const std::string& app, bool isURL)>;

public:
  static BoostEnvironment& forVM(VM vm) {
    return static_cast<BoostEnvironment&>(vm->getEnvironment());
  }

public:
  inline
  BoostEnvironment(const VMStarter& vmStarter, VirtualMachineOptions options);

  inline
  VMIdentifier addVM(const std::string& app, bool isURL);

  inline
  VMIdentifier checkValidIdentifier(VM vm, RichNode identifier);

  inline
  bool findVM(VMIdentifier identifier,
              std::function<void(BoostVM& boostVM)> onSuccess);

  inline
  UnstableNode listVMs(VM vm);

  void killVM(VM vm, nativeint exitCode) {
    killVM(BoostVM::forVM(vm).identifier, exitCode);
  }

  inline
  void killVM(VMIdentifier identifier, nativeint exitCode);

  inline
  void removeTerminatedVM(VMIdentifier identifier,
                          boost::asio::io_service::work* work);

// Configuration

public:
  const BootLoader& getBootLoader() {
    return _bootLoader;
  }

  void setBootLoader(const BootLoader& loader) {
    _bootLoader = loader;
  }

// Run and preemption

public:
  inline
  int runIO();

// Time

  static std::int64_t getReferenceTime() {
    return ptimeToReferenceTime(
      boost::posix_time::microsec_clock::universal_time());
  }

  static boost::posix_time::ptime referenceTimeToPTime(std::int64_t time) {
    return epoch() + boost::posix_time::millisec(time);
  }

  static std::int64_t ptimeToReferenceTime(boost::posix_time::ptime time) {
    return (time - epoch()).total_milliseconds();
  }

  static boost::posix_time::ptime epoch() {
    using namespace boost::gregorian;
    return boost::posix_time::ptime(date(1970, Jan, 1));
  }

// UUID generation

public:
  UUID genUUID(VM vm) {
    return BoostVM::forVM(vm).genUUID();
  }

// BigInt

public:
  std::shared_ptr<BigIntImplem> newBigIntImplem(VM vm, nativeint value) {
    return BoostBigInt::make_shared_ptr(value);
  }

  std::shared_ptr<BigIntImplem> newBigIntImplem(VM vm, double value) {
    return BoostBigInt::make_shared_ptr(value);
  }

  std::shared_ptr<BigIntImplem> newBigIntImplem(VM vm, const std::string& value) {
    return BoostBigInt::make_shared_ptr(value);
  }

// VM Port
public:
  inline
  void sendOnVMPort(VM from, VMIdentifier to, RichNode value);

// GC
public:
  void gCollect(GC gc) {
    BoostVM::forVM(gc->vm).gCollect(gc);
  }

// VMs
private:
  std::forward_list<BoostVM> vms;
  VMIdentifier _nextVMIdentifier;
  nativeint _exitCode;
  std::mutex _vmsMutex; // protects vms, _nextVMIdentifier and _exitCode

  VirtualMachineOptions _options;

// Bootstrap
private:
  BootLoader _bootLoader;

public:
  VMStarter vmStarter;

// ASIO service
public:
  boost::asio::io_service io_service;
};

///////////////
// Utilities //
///////////////

template <typename T>
inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  nativeint errnum, T&& message);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function, int errnum);

inline
void MOZART_NORETURN raiseLastOSError(VM vm, const char* function);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  boost::system::error_code& ec);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  const boost::system::system_error& error);

} }

#endif // MOZART_BOOSTENV_DECL_H
<commit_msg>Unify spacing in BoostEnvironment declaration<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZART_BOOSTENV_DECL_H
#define MOZART_BOOSTENV_DECL_H

#include <mozart.hh>

#include <ctime>
#include <cstdio>
#include <cerrno>
#include <forward_list>
#include <mutex>

#include <boost/thread.hpp>

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include "boostvm-decl.hh"
#include "boostenvbigint-decl.hh"

namespace mozart { namespace boostenv {

//////////////////////
// BoostEnvironment //
//////////////////////

class BoostEnvironment: public VirtualMachineEnvironment {
private:
  using BootLoader = std::function<bool(VM vm, const std::string& url,
                                        UnstableNode& result)>;
  using VMStarter = std::function<bool(VM vm, const std::string& app, bool isURL)>;

public:
  static BoostEnvironment& forVM(VM vm) {
    return static_cast<BoostEnvironment&>(vm->getEnvironment());
  }

public:
  inline
  BoostEnvironment(const VMStarter& vmStarter, VirtualMachineOptions options);

// VM Management

public:
  inline
  VMIdentifier addVM(const std::string& app, bool isURL);

  inline
  VMIdentifier checkValidIdentifier(VM vm, RichNode identifier);

  inline
  bool findVM(VMIdentifier identifier,
              std::function<void(BoostVM& boostVM)> onSuccess);

  inline
  UnstableNode listVMs(VM vm);

  void killVM(VM vm, nativeint exitCode) {
    killVM(BoostVM::forVM(vm).identifier, exitCode);
  }

  inline
  void killVM(VMIdentifier identifier, nativeint exitCode);

  inline
  void removeTerminatedVM(VMIdentifier identifier,
                          boost::asio::io_service::work* work);

// Configuration

public:
  const BootLoader& getBootLoader() {
    return _bootLoader;
  }

  void setBootLoader(const BootLoader& loader) {
    _bootLoader = loader;
  }

// Run and preemption

public:
  inline
  int runIO();

// Time

  static std::int64_t getReferenceTime() {
    return ptimeToReferenceTime(
      boost::posix_time::microsec_clock::universal_time());
  }

  static boost::posix_time::ptime referenceTimeToPTime(std::int64_t time) {
    return epoch() + boost::posix_time::millisec(time);
  }

  static std::int64_t ptimeToReferenceTime(boost::posix_time::ptime time) {
    return (time - epoch()).total_milliseconds();
  }

  static boost::posix_time::ptime epoch() {
    using namespace boost::gregorian;
    return boost::posix_time::ptime(date(1970, Jan, 1));
  }

// UUID generation

public:
  UUID genUUID(VM vm) {
    return BoostVM::forVM(vm).genUUID();
  }

// BigInt

public:
  std::shared_ptr<BigIntImplem> newBigIntImplem(VM vm, nativeint value) {
    return BoostBigInt::make_shared_ptr(value);
  }

  std::shared_ptr<BigIntImplem> newBigIntImplem(VM vm, double value) {
    return BoostBigInt::make_shared_ptr(value);
  }

  std::shared_ptr<BigIntImplem> newBigIntImplem(VM vm, const std::string& value) {
    return BoostBigInt::make_shared_ptr(value);
  }

// VM Port

public:
  inline
  void sendOnVMPort(VM from, VMIdentifier to, RichNode value);

// GC

public:
  void gCollect(GC gc) {
    BoostVM::forVM(gc->vm).gCollect(gc);
  }

// VMs
private:
  std::forward_list<BoostVM> vms;
  VMIdentifier _nextVMIdentifier;
  nativeint _exitCode;
  std::mutex _vmsMutex; // protects vms, _nextVMIdentifier and _exitCode

  VirtualMachineOptions _options;

// Bootstrap
private:
  BootLoader _bootLoader;
public:
  VMStarter vmStarter;

// ASIO service
public:
  boost::asio::io_service io_service;
};

///////////////
// Utilities //
///////////////

template <typename T>
inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  nativeint errnum, T&& message);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function, int errnum);

inline
void MOZART_NORETURN raiseLastOSError(VM vm, const char* function);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  boost::system::error_code& ec);

inline
void MOZART_NORETURN raiseOSError(VM vm, const char* function,
                                  const boost::system::system_error& error);

} }

#endif // MOZART_BOOSTENV_DECL_H
<|endoftext|>