<commit_before>#include "logics/tagrepository.h"
#include <TWebApplication>
#include <QJsonObject>
#include <QJsonDocument>

// make symlink for `tags` to public
namespace {
    struct TagDirMakePublicLink {
        TagDirMakePublicLink() {
            const QString sourcePath = TagRepository().baseDir().absolutePath();
            const QString linkPath = QDir(Tf::app()->publicPath()).absoluteFilePath(QFileInfo(sourcePath).fileName());
            QFile::link(sourcePath, linkPath);
        };
    } TagDirMakePublicLink;
};

TagRepository::TagRepository()
    : _baseDir(Tf::conf("settings").value("TagsDir").toString())
{
}

TagRepository::TagRepository(const QDir& listDir)
    : _baseDir(listDir)
{
}

QList<TagGroup>
TagRepository::allGroups() const
{
    QList<TagGroup> groups;

    if (_baseDir.exists()) {
        for (const QString& name : _baseDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::Name)) {
            groups << TagGroup(_baseDir, name);
        }
    }

    return groups;
}

TagGroup
TagRepository::createGroup(const QString& groupName) const
{
    TagGroup created;
    if (! groupName.isEmpty()) {
        if (_baseDir.mkpath(groupName)) {
            created = TagGroup(_baseDir, groupName);
        }
    }
    return created;
}

bool
TagRepository::destroyGroup(const QString& groupName) const
{
    bool destroyed = false;
    if (findGroup(groupName).exists()) {
        destroyed = QDir(_baseDir.filePath(groupName)).removeRecursively();
    }
    return destroyed;
}

TagGroup
TagRepository::findGroup(const QString& groupName) const
{
    TagGroup found;
    if (! groupName.isEmpty()) {
        if (_baseDir.exists(groupName)) {
            found = TagGroup(_baseDir, groupName);
        }
    }
    return found;
}

bool
TagRepository::saveGroup(TagGroup& group)
{
    bool created = false;
    const QString groupName(group.name());
    if (! groupName.isEmpty()) {
        created = _baseDir.mkpath(groupName);
        if (created) {
            group.setDirectory(_baseDir);
        }
    }
    return created;
}

QList<Tag>
TagRepository::allTags() const
{
    QList<Tag> tags;

    for (const TagGroup& group : allGroups()) {
        tags << group.tags();
    }

    return tags;
}

Tag
TagRepository::createTag(const QString& groupName, const QString& tagName, const QString& tagDisplayName)
{
    TagGroup group = findGroup(groupName);
    if (! group.exists()) {
        group = createGroup(groupName);
    }

    Tag created = group.createTag(tagName);
    if (created.exists()) {
        created.setDisplayName(tagDisplayName);

        QStringList alltags;
        for (auto& tag : TagRepository().allTags()) {
            alltags << tag.name();
        }

        // Tag name is system unique.
        if (alltags.filter(tagName).count() > 1) {
            created.destroy();
        }
    }

    return created;
}

bool
TagRepository::destroyTag(const QString& groupName, const QString& tagName)
{
    return findGroup(groupName).destroyTag(tagName);
}

bool
TagRepository::destroyTag(const QString& tagName)
{
    return findTag(tagName).destroy();
}

Tag
TagRepository::findTag(const QString& tagName) const
{
    Tag found;
    if (! tagName.isEmpty()) {
        for (const TagGroup& group : allGroups()) {
            found = group.findTag(tagName);
            if (found.exists()) break;
        }
    }
    return found;
}

bool
TagRepository::updateTag(const QString& groupName, const QString& tagName, const QVariantMap& changes)
{
    Tag sourceTag = findGroup(groupName).findTag(tagName);
    if (sourceTag.exists()) {
        return updateTag(sourceTag, changes);
    }
    return false;
}

bool
TagRepository::updateTag(const QString& tagName, const QVariantMap& changes)
{
    Tag sourceTag = findTag(tagName);
    if (sourceTag.exists()) {
        return updateTag(sourceTag, changes);
    }
    return false;
}

bool
TagRepository::updateTag(Tag& sourceTag, const QVariantMap& changes)
{
    bool succeed = false;

    if (sourceTag.exists()) {
        const QString name = changes.value("name").toString();
        if ((! name.isEmpty()) && (name != sourceTag.name())) {
            // tag name is system unique
            if (findTag(name).exists()) {
                return false;
            }
            succeed = sourceTag.setName(name);
        }

        const QString displayName = changes.value("displayName").toString();
        if ((! displayName.isEmpty()) && (displayName != sourceTag.displayName())) {
            sourceTag.setDisplayName(displayName);
            succeed = true;
        }

        const QString groupName = changes.value("groupName").toString();
        if ((! groupName.isEmpty()) && (groupName != sourceTag.groupName())) {
            TagGroup destinationGroup = findGroup(groupName);
            if (destinationGroup.exists()) {
                succeed = destinationGroup.saveTag(sourceTag);
            }
        }
    }

    return succeed;
}

void
TagRepository::appendImages(const QStringList& images, const QString& groupName, const QString& tagName)
{
    const TagGroup group = findGroup(groupName);
    if ((! group.exists()) || (! group.hasTag(tagName))) {
        createTag(groupName, tagName);
    }

    const Tag tag = group.findTag(tagName);
    for (const QString& path : images) {
        tag.appendImage(path);
        generateTagResolution(path);
    }
}

void
TagRepository::removeImages(const QStringList& images, const QString& groupName, const QString& tagName)
{
    const TagGroup group = findGroup(groupName);
    if ((! group.exists()) || (! group.hasTag(tagName))) {
        return;
    }

    const Tag tag = group.findTag(tagName);
    for (const QString& path : images) {
        tag.removeImage(QFileInfo(path).fileName());
        generateTagResolution(path);
    }
}

void
TagRepository::updateImages(const QStringList& images, const QString& groupName, const QString& tagName)
{
    TagGroup group = findGroup(groupName);
    Tag tag = group.findTag(tagName);

    for (const QString& path : images) {
        if (! tagName.isEmpty()) {
            tag.appendImage(path);
        }
        for (const Tag& otherTag : group.tags()) {
            if (otherTag.name() != tagName) {
                otherTag.removeImage(QFileInfo(path).fileName());
            }
        }
        generateTagResolution(path);
    }
}

void
TagRepository::updateImages(const QStringList& images, const QVariantMap& tags)
{
    for (const QString& groupName : tags.keys()) {
        const QString tagName = tags.value(groupName).toString();
        updateImages(images, groupName, tagName);
    }
}

QDir
TagRepository::baseDir() const
{
    return _baseDir;
}

QList<Tag>
TagRepository::getTags(const QString& image) const
{
    static const auto TagResolutionDir = QDir(Tf::conf("settings").value("TagResolutionDir").toString());
    QList<Tag> tags;
    QFileInfo fi(image);
    QFile resolveJson(TagResolutionDir.absoluteFilePath(fi.completeBaseName() + ".json"));

    if (! resolveJson.exists()) {
        generateTagResolution(image);
    }

    if (resolveJson.open(QIODevice::ReadOnly)) {
        // Read from JSON
        auto json = resolveJson.readAll();
        resolveJson.close();

        auto tagobj = QJsonDocument::fromJson(json).object().value("tags").toObject();
        if (! json.isEmpty()) {
            bool regen = false;

            for (auto it = tagobj.constBegin(); it != tagobj.constEnd(); ++it) {
                Tag t = findGroup(it.key()).findTag(it.value().toString());
                if (t.exists()) {
                    tags << t;
                } else {
                    regen = true;
                }
            }

            if (regen) {
                // Regenerates
                generateTagResolution(image);
            }
            return tags;
        }
    }

    tError() << "Tag resolution error : " << fi.fileName();
    return tags;
}

static bool
generateTagResolutionFile(const QString& image, const QList<TagGroup>& allGroups)
{
    static const auto TagResolutionDir = QDir(Tf::conf("settings").value("TagResolutionDir").toString());
    const QFileInfo fi(image);
    const QString filename = fi.fileName();

    QJsonObject tagObj;
    for (const TagGroup& g : allGroups) {
        for (const Tag& t : g.tags()) {
            if (t.hasImage(filename)) {
                tagObj.insert(g.name(), t.name());
            }
        }
    }

    QJsonObject json;
    json.insert("tags", tagObj);
    auto jsondata = QJsonDocument(json).toJson(QJsonDocument::Compact);

    if (! TagResolutionDir.exists()) {
        TagResolutionDir.mkpath(".");
    }

    QFile resolveJson(TagResolutionDir.absoluteFilePath(fi.completeBaseName() + ".json"));
    if (resolveJson.exists() && resolveJson.open(QIODevice::ReadOnly)) {
        auto currentJson = resolveJson.readAll();
        resolveJson.close();

        if (currentJson == jsondata) {
            // not write
            return true;
        }
    }

    if (resolveJson.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        resolveJson.write(jsondata);
        resolveJson.close();
        tInfo() << "tag resolution json created: " << resolveJson.fileName();
    } else {
        tError() << "write error tag resolution json: " << resolveJson.fileName();
        return false;
    }
    return true;
}

bool
TagRepository::generateTagResolution(const QString& image) const
{
    return generateTagResolutionFile(image, allGroups());
}

void
TagRepository::regenerateTagResolution() const
{
    static const auto OriginalImagesDir = Tf::conf("settings").value("OriginalImagesDir").toString();
    const auto allgroups = allGroups();

    QDirIterator it(OriginalImagesDir, {"*.jpg", "*.jpeg"}, QDir::Files | QDir::Readable, QDirIterator::Subdirectories);
    while (it.hasNext()) {
        generateTagResolutionFile(it.next(), allgroups);
    }
}

/* JSON sample
{
    "tags": {
        "フォルダ（大腸炎）": "ulcerativecolitis_0630_001-420_mayo2_r",
        "全体病変": "ulcerativecolitis_mayo2",
        "照明": "normal",
        "部位": "e07daichorectum"
    }
}
*/
<commit_msg>Fix makeshift<commit_after>#include "logics/tagrepository.h"
#include <TWebApplication>
#include <QJsonObject>
#include <QJsonDocument>
#include <QtConcurrent>

// make symlink for `tags` to public
namespace {
    struct TagDirMakePublicLink {
        TagDirMakePublicLink() {
            const QString sourcePath = TagRepository().baseDir().absolutePath();
            const QString linkPath = QDir(Tf::app()->publicPath()).absoluteFilePath(QFileInfo(sourcePath).fileName());
            QFile::link(sourcePath, linkPath);
        };
    } TagDirMakePublicLink;
};

TagRepository::TagRepository()
    : _baseDir(Tf::conf("settings").value("TagsDir").toString())
{
}

TagRepository::TagRepository(const QDir& listDir)
    : _baseDir(listDir)
{
}

QList<TagGroup>
TagRepository::allGroups() const
{
    QList<TagGroup> groups;

    if (_baseDir.exists()) {
        for (const QString& name : _baseDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::Name)) {
            groups << TagGroup(_baseDir, name);
        }
    }

    return groups;
}

TagGroup
TagRepository::createGroup(const QString& groupName) const
{
    TagGroup created;
    if (! groupName.isEmpty()) {
        if (_baseDir.mkpath(groupName)) {
            created = TagGroup(_baseDir, groupName);
        }
    }
    return created;
}

bool
TagRepository::destroyGroup(const QString& groupName) const
{
    bool destroyed = false;
    if (findGroup(groupName).exists()) {
        destroyed = QDir(_baseDir.filePath(groupName)).removeRecursively();
    }
    return destroyed;
}

TagGroup
TagRepository::findGroup(const QString& groupName) const
{
    TagGroup found;
    if (! groupName.isEmpty()) {
        if (_baseDir.exists(groupName)) {
            found = TagGroup(_baseDir, groupName);
        }
    }
    return found;
}

bool
TagRepository::saveGroup(TagGroup& group)
{
    bool created = false;
    const QString groupName(group.name());
    if (! groupName.isEmpty()) {
        created = _baseDir.mkpath(groupName);
        if (created) {
            group.setDirectory(_baseDir);
        }
    }
    return created;
}

QList<Tag>
TagRepository::allTags() const
{
    QList<Tag> tags;

    for (const TagGroup& group : allGroups()) {
        tags << group.tags();
    }

    return tags;
}

Tag
TagRepository::createTag(const QString& groupName, const QString& tagName, const QString& tagDisplayName)
{
    TagGroup group = findGroup(groupName);
    if (! group.exists()) {
        group = createGroup(groupName);
    }

    Tag created = group.createTag(tagName);
    if (created.exists()) {
        created.setDisplayName(tagDisplayName);

        QStringList alltags;
        for (auto& tag : TagRepository().allTags()) {
            alltags << tag.name();
        }

        // Tag name is system unique.
        if (alltags.filter(tagName).count() > 1) {
            created.destroy();
        }
    }

    return created;
}

bool
TagRepository::destroyTag(const QString& groupName, const QString& tagName)
{
    return findGroup(groupName).destroyTag(tagName);
}

bool
TagRepository::destroyTag(const QString& tagName)
{
    return findTag(tagName).destroy();
}

Tag
TagRepository::findTag(const QString& tagName) const
{
    Tag found;
    if (! tagName.isEmpty()) {
        for (const TagGroup& group : allGroups()) {
            found = group.findTag(tagName);
            if (found.exists()) break;
        }
    }
    return found;
}

bool
TagRepository::updateTag(const QString& groupName, const QString& tagName, const QVariantMap& changes)
{
    Tag sourceTag = findGroup(groupName).findTag(tagName);
    if (sourceTag.exists()) {
        return updateTag(sourceTag, changes);
    }
    return false;
}

bool
TagRepository::updateTag(const QString& tagName, const QVariantMap& changes)
{
    Tag sourceTag = findTag(tagName);
    if (sourceTag.exists()) {
        return updateTag(sourceTag, changes);
    }
    return false;
}

bool
TagRepository::updateTag(Tag& sourceTag, const QVariantMap& changes)
{
    bool succeed = false;

    if (sourceTag.exists()) {
        const QString name = changes.value("name").toString();
        if ((! name.isEmpty()) && (name != sourceTag.name())) {
            // tag name is system unique
            if (findTag(name).exists()) {
                return false;
            }
            succeed = sourceTag.setName(name);
        }

        const QString displayName = changes.value("displayName").toString();
        if ((! displayName.isEmpty()) && (displayName != sourceTag.displayName())) {
            sourceTag.setDisplayName(displayName);
            succeed = true;
        }

        const QString groupName = changes.value("groupName").toString();
        if ((! groupName.isEmpty()) && (groupName != sourceTag.groupName())) {
            TagGroup destinationGroup = findGroup(groupName);
            if (destinationGroup.exists()) {
                succeed = destinationGroup.saveTag(sourceTag);
            }
        }
    }

    return succeed;
}

void
TagRepository::appendImages(const QStringList& images, const QString& groupName, const QString& tagName)
{
    const TagGroup group = findGroup(groupName);
    if ((! group.exists()) || (! group.hasTag(tagName))) {
        createTag(groupName, tagName);
    }

    const Tag tag = group.findTag(tagName);
    for (const QString& path : images) {
        tag.appendImage(path);
        QtConcurrent::run([=]{
            generateTagResolution(path);
        });
    }
}

void
TagRepository::removeImages(const QStringList& images, const QString& groupName, const QString& tagName)
{
    const TagGroup group = findGroup(groupName);
    if ((! group.exists()) || (! group.hasTag(tagName))) {
        return;
    }

    const Tag tag = group.findTag(tagName);
    for (const QString& path : images) {
        tag.removeImage(QFileInfo(path).fileName());
        QtConcurrent::run([=]{
            generateTagResolution(path);
        });
    }
}

void
TagRepository::updateImages(const QStringList& images, const QString& groupName, const QString& tagName)
{
    TagGroup group = findGroup(groupName);
    Tag tag = group.findTag(tagName);

    for (const QString& path : images) {
        if (! tagName.isEmpty()) {
            tag.appendImage(path);
        }
        for (const Tag& otherTag : group.tags()) {
            if (otherTag.name() != tagName) {
                otherTag.removeImage(QFileInfo(path).fileName());
            }
        }
        QtConcurrent::run([=]{
            generateTagResolution(path);
        });
    }
}

void
TagRepository::updateImages(const QStringList& images, const QVariantMap& tags)
{
    for (const QString& groupName : tags.keys()) {
        const QString tagName = tags.value(groupName).toString();
        updateImages(images, groupName, tagName);
    }
}

QDir
TagRepository::baseDir() const
{
    return _baseDir;
}

QList<Tag>
TagRepository::getTags(const QString& image) const
{
    static const auto TagResolutionDir = QDir(Tf::conf("settings").value("TagResolutionDir").toString());
    QList<Tag> tags;
    QFileInfo fi(image);
    QFile resolveJson(TagResolutionDir.absoluteFilePath(fi.completeBaseName() + ".json"));

    if (! resolveJson.exists()) {
        generateTagResolution(image);
    }

    if (resolveJson.open(QIODevice::ReadOnly)) {
        // Read from JSON
        auto json = resolveJson.readAll();
        resolveJson.close();

        auto tagobj = QJsonDocument::fromJson(json).object().value("tags").toObject();
        if (! json.isEmpty()) {
            bool regen = false;

            for (auto it = tagobj.constBegin(); it != tagobj.constEnd(); ++it) {
                Tag t = findGroup(it.key()).findTag(it.value().toString());
                if (t.exists()) {
                    tags << t;
                } else {
                    regen = true;
                }
            }

            if (regen) {
                // Regenerates
                generateTagResolution(image);
            }
            return tags;
        }
    }

    tError() << "Tag resolution error : " << fi.fileName();
    return tags;
}

static bool
generateTagResolutionFile(const QString& image, const QList<TagGroup>& allGroups)
{
    static const auto TagResolutionDir = QDir(Tf::conf("settings").value("TagResolutionDir").toString());
    const QFileInfo fi(image);
    const QString filename = fi.fileName();

    QJsonObject tagObj;
    for (const TagGroup& g : allGroups) {
        for (const Tag& t : g.tags()) {
            if (t.hasImage(filename)) {
                tagObj.insert(g.name(), t.name());
            }
        }
    }

    QJsonObject json;
    json.insert("tags", tagObj);
    auto jsondata = QJsonDocument(json).toJson(QJsonDocument::Compact);

    if (! TagResolutionDir.exists()) {
        TagResolutionDir.mkpath(".");
    }

    QFile resolveJson(TagResolutionDir.absoluteFilePath(fi.completeBaseName() + ".json"));
    if (resolveJson.exists() && resolveJson.open(QIODevice::ReadOnly)) {
        auto currentJson = resolveJson.readAll();
        resolveJson.close();

        if (currentJson == jsondata) {
            // not write
            return true;
        }
    }

    if (resolveJson.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        resolveJson.write(jsondata);
        resolveJson.close();
        tInfo() << "tag resolution json created: " << resolveJson.fileName();
    } else {
        tError() << "write error tag resolution json: " << resolveJson.fileName();
        return false;
    }
    return true;
}

bool
TagRepository::generateTagResolution(const QString& image) const
{
    return generateTagResolutionFile(image, allGroups());
}

void
TagRepository::regenerateTagResolution() const
{
    static const auto OriginalImagesDir = Tf::conf("settings").value("OriginalImagesDir").toString();
    const auto allgroups = allGroups();

    QDirIterator it(OriginalImagesDir, {"*.jpg", "*.jpeg"}, QDir::Files | QDir::Readable, QDirIterator::Subdirectories);
    while (it.hasNext()) {
        generateTagResolutionFile(it.next(), allgroups);
    }
}

/* JSON sample
{
    "tags": {
        "フォルダ（大腸炎）": "ulcerativecolitis_0630_001-420_mayo2_r",
        "全体病変": "ulcerativecolitis_mayo2",
        "照明": "normal",
        "部位": "e07daichorectum"
    }
}
*/
<|endoftext|>


<commit_before>/*****************************************************************************
 * timer.cpp : wxWindows plugin for vlc
 *****************************************************************************
 * Copyright (C) 2000-2003 VideoLAN
 * $Id$
 *
 * Authors: Gildas Bazin <gbazin@videolan.org>
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <errno.h>                                                 /* ENOMEM */
#include <string.h>                                            /* strerror() */
#include <stdio.h>

#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/intf.h>

#include "wxwindows.h"
#include <wx/timer.h>

//void DisplayStreamDate( wxControl *, intf_thread_t *, int );

/* Callback prototypes */
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
                        vlc_value_t old_val, vlc_value_t new_val, void *param );
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param );

/*****************************************************************************
 * Constructor.
 *****************************************************************************/
Timer::Timer( intf_thread_t *_p_intf, Interface *_p_main_interface )
{
    p_intf = _p_intf;
    p_main_interface = _p_main_interface;
    b_init = 0;
    i_old_playing_status = PAUSE_S;
    i_old_rate = INPUT_RATE_DEFAULT;

    /* Register callback for the intf-popupmenu variable */
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist != NULL )
    {
        var_AddCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
        var_AddCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
        vlc_object_release( p_playlist );
    }

    Start( 100 /*milliseconds*/, wxTIMER_CONTINUOUS );
}

Timer::~Timer()
{
    /* Unregister callback */
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist != NULL )
    {
        var_DelCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
        var_DelCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
        vlc_object_release( p_playlist );
    }
}

/*****************************************************************************
 * Private methods.
 *****************************************************************************/

/*****************************************************************************
 * Manage: manage main thread messages
 *****************************************************************************
 * In this function, called approx. 10 times a second, we check what the
 * main program wanted to tell us.
 *****************************************************************************/
void Timer::Notify()
{
    input_thread_t *p_input = NULL;
#if defined( __WXMSW__ ) /* Work-around a bug with accelerators */
    if( !b_init )
    {
        p_main_interface->Init();
        b_init = VLC_TRUE;
    }
#endif

    vlc_mutex_lock( &p_intf->change_lock );

    /* Update the input */
    if( p_intf->p_sys->p_input == NULL )
    {
        playlist_t *p_playlist =
            (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
        if( p_playlist != NULL )
        {
            p_intf->p_sys->p_input = p_playlist->p_input;
            vlc_object_release( p_playlist );
        }

        /* Refresh interface */
        if( p_intf->p_sys->p_input )
        {
            p_main_interface->slider->SetValue( 0 );
            b_old_seekable = VLC_FALSE;
            b_disc_shown = VLC_FALSE;

            p_main_interface->statusbar->SetStatusText(
                wxU(p_intf->p_sys->p_input->input.p_item->psz_name), 2 );

            p_main_interface->TogglePlayButton( PLAYING_S );
            i_old_playing_status = PLAYING_S;
        }
    }
    else if( p_intf->p_sys->p_input->b_dead )
    {
        /* Hide slider and Disc Buttons */
        p_main_interface->disc_frame->Hide();
        p_main_interface->slider_sizer->Hide(
            p_main_interface->disc_frame );
        p_main_interface->slider_sizer->Layout();
        p_main_interface->slider_sizer->Fit( p_main_interface->slider_frame );

        p_main_interface->slider_frame->Hide();
        p_main_interface->frame_sizer->Hide(
            p_main_interface->slider_frame );
        p_main_interface->frame_sizer->Layout();
        p_main_interface->frame_sizer->Fit( p_main_interface );

        p_main_interface->TogglePlayButton( PAUSE_S );
        i_old_playing_status = PAUSE_S;

        p_main_interface->statusbar->SetStatusText( wxT(""), 0 );
        p_main_interface->statusbar->SetStatusText( wxT(""), 2 );

        p_intf->p_sys->p_input = NULL;
    }

    if( p_intf->p_sys->p_input )
    {
        input_thread_t *p_input = p_intf->p_sys->p_input;
        vlc_value_t val;

        if( !p_input->b_die )
        {
            vlc_value_t pos;

            /* New input or stream map change */
            p_intf->p_sys->b_playing = 1;

            /* Update the item name */
            p_main_interface->statusbar->SetStatusText(
                wxU(p_intf->p_sys->p_input->input.p_item->psz_name), 2 );

            /* Manage the slider */
            /* FIXME --fenrir */
            /* Change the name of b_old_seekable into b_show_bar or something like that */
            var_Get( p_input, "position", &pos );

            vlc_value_t val;
            var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
            if( val.i_int > 0 && !b_disc_shown )
            {
                b_disc_shown = VLC_TRUE;
                vlc_value_t val;

                    #define HELP_MENU N_("Menu")
                    #define HELP_PCH N_("Previous chapter")
                    #define HELP_NCH N_("Next chapter")
                    #define HELP_PTR N_("Previous track")
                    #define HELP_NTR N_("Next track")

                var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val,
                            NULL );

                if( val.i_int > 0 )
                {
                    p_main_interface->disc_menu_button->Show();
                    p_main_interface->disc_sizer->Show(
                        p_main_interface->disc_menu_button );
                    p_main_interface->disc_sizer->Layout();
                    p_main_interface->disc_sizer->Fit(
                        p_main_interface->disc_frame );

                    p_main_interface->disc_menu_button->SetToolTip(
                        wxU(_( HELP_MENU ) ) );
                    p_main_interface->disc_prev_button->SetToolTip(
                        wxU(_( HELP_PCH ) ) );
                    p_main_interface->disc_next_button->SetToolTip(
                        wxU(_( HELP_NCH ) ) );
                }
                else
                {
                    p_main_interface->disc_menu_button->Hide();
                    p_main_interface->disc_sizer->Hide(
                        p_main_interface->disc_menu_button );

                    p_main_interface->disc_prev_button->SetToolTip(
                        wxU(_( HELP_PTR ) ) );
                    p_main_interface->disc_next_button->SetToolTip(
                        wxU(_( HELP_NTR ) ) );
                }

                p_main_interface->disc_frame->Show();
                p_main_interface->slider_sizer->Show(
                    p_main_interface->disc_frame );
            }

            if( ! b_old_seekable )
            {
                if( pos.f_float > 0.0 )
                {
                    /* Done like this, as it's the only way to know if the */
                    /* slider has to be displayed */
                    b_old_seekable = VLC_TRUE;
                    p_main_interface->slider_frame->Show();
                    p_main_interface->frame_sizer->Show(
                        p_main_interface->slider_frame );
                    p_main_interface->frame_sizer->Layout();
                    p_main_interface->frame_sizer->Fit( p_main_interface );
                }
            }

            if( p_intf->p_sys->b_playing && b_old_seekable )
            {
                /* Update the slider if the user isn't dragging it. */
                if( p_intf->p_sys->b_slider_free )
                {
                    char psz_time[ MSTRTIME_MAX_SIZE ];
                    char psz_total[ MSTRTIME_MAX_SIZE ];
                    vlc_value_t time;
                    mtime_t i_seconds;

                    /* Update the value */
                    if( pos.f_float >= 0.0 )
                    {
                        p_intf->p_sys->i_slider_pos =
                            (int)(SLIDER_MAX_POS * pos.f_float);

                        p_main_interface->slider->SetValue(
                            p_intf->p_sys->i_slider_pos );

                        var_Get( p_intf->p_sys->p_input, "time", &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_time, i_seconds );

                        var_Get( p_intf->p_sys->p_input, "length",  &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_total, i_seconds );

                        p_main_interface->statusbar->SetStatusText(
                            wxU(psz_time) + wxString(wxT(" / ")) +
                            wxU(psz_total), 0 );
                    }
                }
            }
#if 0
        vlc_mutex_lock( &p_input->stream.stream_lock );
            if( p_intf->p_sys->p_input->stream.b_seekable && !b_old_seekable )
            {
                /* Done like this because b_seekable is set slightly after
                 * the new input object is available. */
                b_old_seekable = VLC_TRUE;
                p_main_interface->slider_frame->Show();
                p_main_interface->frame_sizer->Show(
                    p_main_interface->slider_frame );
                p_main_interface->frame_sizer->Layout();
                p_main_interface->frame_sizer->Fit( p_main_interface );
            }
            if( p_input->stream.b_seekable && p_intf->p_sys->b_playing )
            {
                /* Update the slider if the user isn't dragging it. */
                if( p_intf->p_sys->b_slider_free )
                {
                    vlc_value_t pos;
                    char psz_time[ MSTRTIME_MAX_SIZE ];
                    char psz_total[ MSTRTIME_MAX_SIZE ];
                    vlc_value_t time;
                    mtime_t i_seconds;

                    /* Update the value */
                    var_Get( p_input, "position", &pos );
                    if( pos.f_float >= 0.0 )
                    {
                        p_intf->p_sys->i_slider_pos =
                            (int)(SLIDER_MAX_POS * pos.f_float);

                        p_main_interface->slider->SetValue(
                            p_intf->p_sys->i_slider_pos );

                        var_Get( p_intf->p_sys->p_input, "time", &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_time, i_seconds );

                        var_Get( p_intf->p_sys->p_input, "length",  &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_total, i_seconds );

                        p_main_interface->statusbar->SetStatusText(
                            wxU(psz_time) + wxString(wxT(" / ")) +
                            wxU(psz_total), 0 );
                    }
                }
            }
        vlc_mutex_unlock( &p_input->stream.stream_lock );
#endif
            /* Take care of the volume, etc... */
            p_main_interface->Update();

            /* Manage Playing status */
            var_Get( p_input, "state", &val );
            if( i_old_playing_status != val.i_int )
            {
                if( val.i_int == PAUSE_S )
                {
                    p_main_interface->TogglePlayButton( PAUSE_S );
                }
                else
                {
                    p_main_interface->TogglePlayButton( PLAYING_S );
                }
                i_old_playing_status = val.i_int;
            }

            /* Manage Speed status */
            var_Get( p_input, "rate", &val );
            if( i_old_rate != val.i_int )
            {
                p_main_interface->statusbar->SetStatusText(
                    wxString::Format(wxT("x%.2f"),
                    (float)INPUT_RATE_DEFAULT / val.i_int ), 1 );
                i_old_rate = val.i_int;
            }
        }

    }
    else if( p_intf->p_sys->b_playing && !p_intf->b_die )
    {
        p_intf->p_sys->b_playing = 0;
        p_main_interface->TogglePlayButton( PAUSE_S );
        i_old_playing_status = PAUSE_S;
    }

    /* Show the interface, if requested */
    if( p_intf->p_sys->b_intf_show )
    {
        p_main_interface->Raise();
        p_intf->p_sys->b_intf_show = VLC_FALSE;
    }

    if( p_intf->b_die )
    {
        vlc_mutex_unlock( &p_intf->change_lock );

        /* Prepare to die, young Skywalker */
        p_main_interface->Close(TRUE);
        return;
    }

    vlc_mutex_unlock( &p_intf->change_lock );
}

/*****************************************************************************
 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
 *  We don't show the menu directly here because we don't want the
 *  caller to block for a too long time.
 *****************************************************************************/
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
                        vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t *p_intf = (intf_thread_t *)param;

    if( p_intf->p_sys->pf_show_dialog )
    {
        p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
                                       new_val.b_bool, 0 );
    }

    return VLC_SUCCESS;
}

/*****************************************************************************
 * IntfShowCB: callback triggered by the intf-show playlist variable.
 *****************************************************************************/
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t *p_intf = (intf_thread_t *)param;
    p_intf->p_sys->b_intf_show = VLC_TRUE;

    return VLC_SUCCESS;
}
<commit_msg>* modules/gui/wxwindows/timer.cpp: don't forget to yield/release the input otherwise you're bound to access an invalid pointer later on.<commit_after>/*****************************************************************************
 * timer.cpp : wxWindows plugin for vlc
 *****************************************************************************
 * Copyright (C) 2000-2003 VideoLAN
 * $Id$
 *
 * Authors: Gildas Bazin <gbazin@videolan.org>
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <errno.h>                                                 /* ENOMEM */
#include <string.h>                                            /* strerror() */
#include <stdio.h>

#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/intf.h>

#include "wxwindows.h"
#include <wx/timer.h>

//void DisplayStreamDate( wxControl *, intf_thread_t *, int );

/* Callback prototypes */
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
                        vlc_value_t old_val, vlc_value_t new_val, void *param );
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param );

/*****************************************************************************
 * Constructor.
 *****************************************************************************/
Timer::Timer( intf_thread_t *_p_intf, Interface *_p_main_interface )
{
    p_intf = _p_intf;
    p_main_interface = _p_main_interface;
    b_init = 0;
    i_old_playing_status = PAUSE_S;
    i_old_rate = INPUT_RATE_DEFAULT;

    /* Register callback for the intf-popupmenu variable */
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist != NULL )
    {
        var_AddCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
        var_AddCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
        vlc_object_release( p_playlist );
    }

    Start( 100 /*milliseconds*/, wxTIMER_CONTINUOUS );
}

Timer::~Timer()
{
    /* Unregister callback */
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist != NULL )
    {
        var_DelCallback( p_playlist, "intf-popupmenu", PopupMenuCB, p_intf );
        var_DelCallback( p_playlist, "intf-show", IntfShowCB, p_intf );
        vlc_object_release( p_playlist );
    }
}

/*****************************************************************************
 * Private methods.
 *****************************************************************************/

/*****************************************************************************
 * Manage: manage main thread messages
 *****************************************************************************
 * In this function, called approx. 10 times a second, we check what the
 * main program wanted to tell us.
 *****************************************************************************/
void Timer::Notify()
{
#if defined( __WXMSW__ ) /* Work-around a bug with accelerators */
    if( !b_init )
    {
        p_main_interface->Init();
        b_init = VLC_TRUE;
    }
#endif

    vlc_mutex_lock( &p_intf->change_lock );

    /* Update the input */
    if( p_intf->p_sys->p_input == NULL )
    {
        playlist_t *p_playlist =
            (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
        if( p_playlist != NULL )
        {
            vlc_mutex_lock( &p_playlist->object_lock );
            p_intf->p_sys->p_input = p_playlist->p_input;
            if( p_intf->p_sys->p_input )
                vlc_object_yield( p_intf->p_sys->p_input );
            vlc_mutex_unlock( &p_playlist->object_lock );
            vlc_object_release( p_playlist );
        }

        /* Refresh interface */
        if( p_intf->p_sys->p_input )
        {
            p_main_interface->slider->SetValue( 0 );
            b_old_seekable = VLC_FALSE;
            b_disc_shown = VLC_FALSE;

            p_main_interface->statusbar->SetStatusText(
                wxU(p_intf->p_sys->p_input->input.p_item->psz_name), 2 );

            p_main_interface->TogglePlayButton( PLAYING_S );
            i_old_playing_status = PLAYING_S;
        }
    }
    else if( p_intf->p_sys->p_input->b_dead )
    {
        /* Hide slider and Disc Buttons */
        p_main_interface->disc_frame->Hide();
        p_main_interface->slider_sizer->Hide(
            p_main_interface->disc_frame );
        p_main_interface->slider_sizer->Layout();
        p_main_interface->slider_sizer->Fit( p_main_interface->slider_frame );

        p_main_interface->slider_frame->Hide();
        p_main_interface->frame_sizer->Hide(
            p_main_interface->slider_frame );
        p_main_interface->frame_sizer->Layout();
        p_main_interface->frame_sizer->Fit( p_main_interface );

        p_main_interface->TogglePlayButton( PAUSE_S );
        i_old_playing_status = PAUSE_S;

        p_main_interface->statusbar->SetStatusText( wxT(""), 0 );
        p_main_interface->statusbar->SetStatusText( wxT(""), 2 );

        vlc_object_release( p_intf->p_sys->p_input );
        p_intf->p_sys->p_input = NULL;
    }

    if( p_intf->p_sys->p_input )
    {
        input_thread_t *p_input = p_intf->p_sys->p_input;
        vlc_value_t val;

        if( !p_input->b_die )
        {
            vlc_value_t pos;

            /* New input or stream map change */
            p_intf->p_sys->b_playing = 1;

            /* Update the item name */
            p_main_interface->statusbar->SetStatusText(
                wxU(p_intf->p_sys->p_input->input.p_item->psz_name), 2 );

            /* Manage the slider */
            /* FIXME --fenrir */
            /* Change the name of b_old_seekable into b_show_bar or something like that */
            var_Get( p_input, "position", &pos );

            var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
            if( val.i_int > 0 && !b_disc_shown )
            {
                b_disc_shown = VLC_TRUE;
                vlc_value_t val;

                    #define HELP_MENU N_("Menu")
                    #define HELP_PCH N_("Previous chapter")
                    #define HELP_NCH N_("Next chapter")
                    #define HELP_PTR N_("Previous track")
                    #define HELP_NTR N_("Next track")

                var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val,
                            NULL );

                if( val.i_int > 0 )
                {
                    p_main_interface->disc_menu_button->Show();
                    p_main_interface->disc_sizer->Show(
                        p_main_interface->disc_menu_button );
                    p_main_interface->disc_sizer->Layout();
                    p_main_interface->disc_sizer->Fit(
                        p_main_interface->disc_frame );

                    p_main_interface->disc_menu_button->SetToolTip(
                        wxU(_( HELP_MENU ) ) );
                    p_main_interface->disc_prev_button->SetToolTip(
                        wxU(_( HELP_PCH ) ) );
                    p_main_interface->disc_next_button->SetToolTip(
                        wxU(_( HELP_NCH ) ) );
                }
                else
                {
                    p_main_interface->disc_menu_button->Hide();
                    p_main_interface->disc_sizer->Hide(
                        p_main_interface->disc_menu_button );

                    p_main_interface->disc_prev_button->SetToolTip(
                        wxU(_( HELP_PTR ) ) );
                    p_main_interface->disc_next_button->SetToolTip(
                        wxU(_( HELP_NTR ) ) );
                }

                p_main_interface->disc_frame->Show();
                p_main_interface->slider_sizer->Show(
                    p_main_interface->disc_frame );
            }

            if( ! b_old_seekable )
            {
                if( pos.f_float > 0.0 )
                {
                    /* Done like this, as it's the only way to know if the */
                    /* slider has to be displayed */
                    b_old_seekable = VLC_TRUE;
                    p_main_interface->slider_frame->Show();
                    p_main_interface->frame_sizer->Show(
                        p_main_interface->slider_frame );
                    p_main_interface->frame_sizer->Layout();
                    p_main_interface->frame_sizer->Fit( p_main_interface );
                }
            }

            if( p_intf->p_sys->b_playing && b_old_seekable )
            {
                /* Update the slider if the user isn't dragging it. */
                if( p_intf->p_sys->b_slider_free )
                {
                    char psz_time[ MSTRTIME_MAX_SIZE ];
                    char psz_total[ MSTRTIME_MAX_SIZE ];
                    vlc_value_t time;
                    mtime_t i_seconds;

                    /* Update the value */
                    if( pos.f_float >= 0.0 )
                    {
                        p_intf->p_sys->i_slider_pos =
                            (int)(SLIDER_MAX_POS * pos.f_float);

                        p_main_interface->slider->SetValue(
                            p_intf->p_sys->i_slider_pos );

                        var_Get( p_intf->p_sys->p_input, "time", &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_time, i_seconds );

                        var_Get( p_intf->p_sys->p_input, "length",  &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_total, i_seconds );

                        p_main_interface->statusbar->SetStatusText(
                            wxU(psz_time) + wxString(wxT(" / ")) +
                            wxU(psz_total), 0 );
                    }
                }
            }
#if 0
        vlc_mutex_lock( &p_input->stream.stream_lock );
            if( p_intf->p_sys->p_input->stream.b_seekable && !b_old_seekable )
            {
                /* Done like this because b_seekable is set slightly after
                 * the new input object is available. */
                b_old_seekable = VLC_TRUE;
                p_main_interface->slider_frame->Show();
                p_main_interface->frame_sizer->Show(
                    p_main_interface->slider_frame );
                p_main_interface->frame_sizer->Layout();
                p_main_interface->frame_sizer->Fit( p_main_interface );
            }
            if( p_input->stream.b_seekable && p_intf->p_sys->b_playing )
            {
                /* Update the slider if the user isn't dragging it. */
                if( p_intf->p_sys->b_slider_free )
                {
                    vlc_value_t pos;
                    char psz_time[ MSTRTIME_MAX_SIZE ];
                    char psz_total[ MSTRTIME_MAX_SIZE ];
                    vlc_value_t time;
                    mtime_t i_seconds;

                    /* Update the value */
                    var_Get( p_input, "position", &pos );
                    if( pos.f_float >= 0.0 )
                    {
                        p_intf->p_sys->i_slider_pos =
                            (int)(SLIDER_MAX_POS * pos.f_float);

                        p_main_interface->slider->SetValue(
                            p_intf->p_sys->i_slider_pos );

                        var_Get( p_intf->p_sys->p_input, "time", &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_time, i_seconds );

                        var_Get( p_intf->p_sys->p_input, "length",  &time );
                        i_seconds = time.i_time / 1000000;
                        secstotimestr ( psz_total, i_seconds );

                        p_main_interface->statusbar->SetStatusText(
                            wxU(psz_time) + wxString(wxT(" / ")) +
                            wxU(psz_total), 0 );
                    }
                }
            }
        vlc_mutex_unlock( &p_input->stream.stream_lock );
#endif
            /* Take care of the volume, etc... */
            p_main_interface->Update();

            /* Manage Playing status */
            var_Get( p_input, "state", &val );
            if( i_old_playing_status != val.i_int )
            {
                if( val.i_int == PAUSE_S )
                {
                    p_main_interface->TogglePlayButton( PAUSE_S );
                }
                else
                {
                    p_main_interface->TogglePlayButton( PLAYING_S );
                }
                i_old_playing_status = val.i_int;
            }

            /* Manage Speed status */
            var_Get( p_input, "rate", &val );
            if( i_old_rate != val.i_int )
            {
                p_main_interface->statusbar->SetStatusText(
                    wxString::Format(wxT("x%.2f"),
                    (float)INPUT_RATE_DEFAULT / val.i_int ), 1 );
                i_old_rate = val.i_int;
            }
        }

    }
    else if( p_intf->p_sys->b_playing && !p_intf->b_die )
    {
        p_intf->p_sys->b_playing = 0;
        p_main_interface->TogglePlayButton( PAUSE_S );
        i_old_playing_status = PAUSE_S;
    }

    /* Show the interface, if requested */
    if( p_intf->p_sys->b_intf_show )
    {
        p_main_interface->Raise();
        p_intf->p_sys->b_intf_show = VLC_FALSE;
    }

    if( p_intf->b_die )
    {
        vlc_mutex_unlock( &p_intf->change_lock );

        /* Prepare to die, young Skywalker */
        p_main_interface->Close(TRUE);
        return;
    }

    vlc_mutex_unlock( &p_intf->change_lock );
}

/*****************************************************************************
 * PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
 *  We don't show the menu directly here because we don't want the
 *  caller to block for a too long time.
 *****************************************************************************/
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
                        vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t *p_intf = (intf_thread_t *)param;

    if( p_intf->p_sys->pf_show_dialog )
    {
        p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU,
                                       new_val.b_bool, 0 );
    }

    return VLC_SUCCESS;
}

/*****************************************************************************
 * IntfShowCB: callback triggered by the intf-show playlist variable.
 *****************************************************************************/
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
                       vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    intf_thread_t *p_intf = (intf_thread_t *)param;
    p_intf->p_sys->b_intf_show = VLC_TRUE;

    return VLC_SUCCESS;
}
<|endoftext|>


<commit_before>// Author: Jan Kristian Sto. Domingo [jstod001@ucr.edu]
// main.cpp for rshell

#include <iostream>

using namespace std;

int main()
{

    return 0;
}

<commit_msg>edited exec.cpp header<commit_after>// Author: Jan Kristian Sto. Domingo [jstod001@ucr.edu]
// exec.cpp for rshell

#include <iostream>

using namespace std;

int main()
{

    return 0;
}

<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Jett
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef HCKT_TREE_H
#define HCKT_TREE_H

#include <cassert>
#include <iostream>
#include <bitset>
#include "lmemvector.hpp"
#include "util.hpp"

namespace hckt
{

template <typename T>
class tree
{
typedef T value_type;

protected:
    std::bitset<64>                     chiset;   //is child set to this position
    std::bitset<64>                     inv_leaf; //opposite of leaf
    hckt::lmemvector<value_type>        values;
    hckt::lmemvector<tree<value_type>*> children;

public:

    tree() : chiset   { 0x0000000000000000 }
           , inv_leaf { 0xFFFFFFFFFFFFFFFF }
           , values   { }
           , children { }
    {
    }

    ~tree()
    {
        collapse();
    }

    //counts number of set bits
    static inline unsigned popcount(std::uint64_t x)
    {
#ifdef __SSE4_2__
        return _popcnt64(x);
#else
        constexpr std::uint64_t m1  { 0x5555555555555555 };
        constexpr std::uint64_t m2  { 0x3333333333333333 };
        constexpr std::uint64_t m4  { 0x0f0f0f0f0f0f0f0f };
        constexpr std::uint64_t h01 { 0x0101010101010101 };

        x -= (x >> 1) & m1;
        x  = (x & m2) + ((x >> 2) & m2);
        x  = (x + (x >> 4)) & m4;

        return (x * h01) >> 56;
#endif
    }

    std::uint64_t chidist() const
    {
        return (chiset.to_ullong() & inv_leaf.to_ullong());
    }

    unsigned children_amnt() const
    {
        return popcount(chidist());
    }

    unsigned leaf_amnt() const
    {
        return popcount(~inv_leaf.to_ullong());
    }

    unsigned value_amount() const
    {
        return popcount(chiset.to_ullong());
    }

    unsigned get_children_position(const unsigned position) const
    {
        assert(position < 64);

        return position == 0 ? position : popcount(chidist() << (64 - position));
    }

    /*
     * check if we have any children
     */
    bool has_children() const
    {
        return chiset.any();
    }

    bool is_set(const unsigned position) const
    {
        assert(position < 64);
        return chiset[position];
    }

    bool is_leaf(const unsigned position) const
    {
        assert(position < 64);
        return !inv_leaf[position];
    }

    /*
     * destroy children
     */
    void collapse()
    {
        const unsigned c_amnt { children_amnt() };

        for(unsigned i=0; i<c_amnt; ++i) {
            children[i]->collapse();
        }

        children.clear(c_amnt);
        values.clear(c_amnt);
        chiset.reset();
    }

    /*
     * insert a tree into position of tree
     * position should be result of get_position
     */
    void insert(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children.insert(cpos, new tree<value_type>(), c_amnt);
        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.set(position);
    }

    /*
     * insert a leaf into position of tree
     * position should be result of get_position
     */
    void insert_leaf(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.reset(position);
    }

    /*
     * removes an item from tree
     * position should be result of get_position
     */
    void remove(const unsigned position)
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children[cpos]->collapse();
        children.erase(cpos);
        values.erase(cpos);
        chiset.reset(position);
    }

    /*
     * get child node
     * position should be result of get_position
     */
    tree<value_type> * child(const unsigned position) const
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos { get_children_position(position) };

        return children[cpos];
    }

    /*
     * sets node to specific value
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    void set_value(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(is_set(position));

        const unsigned cpos { get_children_position(position) };

        values[cpos] = value;
    }

    /*
     * gets value from specific position
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    value_type get_value(const unsigned position) const
    {
        assert(position < 64);

        const unsigned cpos { get_children_position(position) };

        return values[cpos];
    }

    /************************************************
     *
     * BENCHMARKING CODE
     *
     ***********************************************/

    std::size_t calculate_memory_size() const
    {
        const unsigned c_amnt { children_amnt() };
        const unsigned v_amnt { value_amount() };

        std::size_t size {
              sizeof(chiset)
            + sizeof(inv_leaf)
            + sizeof(values)   + (v_amnt * sizeof(value_type))
            + sizeof(children) + (c_amnt * sizeof(tree<value_type>*))
        };

        for(unsigned i=0; i<c_amnt; ++i) {
            size += children[i]->calculate_memory_size();
        }

        return size;
    }

    std::size_t calculate_children_amnt() const
    {
        std::size_t amount { children_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_children_amnt();
        }

        return amount;
    }

    std::size_t calculate_leaf_amount() const
    {
        std::size_t amount { leaf_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_leaf_amount();
        }

        return amount;
    }

    void mem_usage_info() const
    {
        const std::size_t memsize { calculate_memory_size() };
        const std::size_t c_amnt  { calculate_children_amnt() };
        const std::size_t l_amnt  { calculate_leaf_amount() };
        const std::size_t v_amnt  { c_amnt + l_amnt };

        std::cout << "total:     " << hckt::render_size(memsize) << std::endl;

        std::cout << "tree-size: " << hckt::render_size(sizeof(tree<value_type>)) << std::endl;
        std::cout << "val-size:  " << hckt::render_size(sizeof(value_type)) << std::endl;

        std::cout << "values:    " << hckt::render_number(v_amnt) << std::endl;
        std::cout << "children:  " << hckt::render_number(c_amnt) << std::endl;
        std::cout << "leaves:    " << hckt::render_number(l_amnt) << std::endl;

        std::cout << "per-val:   " << (static_cast<double>(memsize) / v_amnt) << " B" << std::endl;
        std::cout << "overhead:  " << (static_cast<double>(memsize - (v_amnt * sizeof(value_type))) / v_amnt) << " B" << std::endl;
    }

};

};

#endif
<commit_msg>use _mm_popcnt<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Jett
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef HCKT_TREE_H
#define HCKT_TREE_H

#include <cassert>
#include <iostream>
#include <bitset>
#include "lmemvector.hpp"
#include "util.hpp"

namespace hckt
{

template <typename T>
class tree
{
typedef T value_type;

protected:
    std::bitset<64>                     chiset;   //is child set to this position
    std::bitset<64>                     inv_leaf; //opposite of leaf
    hckt::lmemvector<value_type>        values;
    hckt::lmemvector<tree<value_type>*> children;

public:

    tree() : chiset   { 0x0000000000000000 }
           , inv_leaf { 0xFFFFFFFFFFFFFFFF }
           , values   { }
           , children { }
    {
    }

    ~tree()
    {
        collapse();
    }

    //counts number of set bits
    static inline unsigned popcount(std::uint64_t x)
    {
#ifdef __SSE4_2__
        return _mm_popcnt_u64(x);
#else
        constexpr std::uint64_t m1  { 0x5555555555555555 };
        constexpr std::uint64_t m2  { 0x3333333333333333 };
        constexpr std::uint64_t m4  { 0x0f0f0f0f0f0f0f0f };
        constexpr std::uint64_t h01 { 0x0101010101010101 };

        x -= (x >> 1) & m1;
        x  = (x & m2) + ((x >> 2) & m2);
        x  = (x + (x >> 4)) & m4;

        return (x * h01) >> 56;
#endif
    }

    std::uint64_t chidist() const
    {
        return (chiset.to_ullong() & inv_leaf.to_ullong());
    }

    unsigned children_amnt() const
    {
        return popcount(chidist());
    }

    unsigned leaf_amnt() const
    {
        return popcount(~inv_leaf.to_ullong());
    }

    unsigned value_amount() const
    {
        return popcount(chiset.to_ullong());
    }

    unsigned get_children_position(const unsigned position) const
    {
        assert(position < 64);

        return position == 0 ? position : popcount(chidist() << (64 - position));
    }

    /*
     * check if we have any children
     */
    bool has_children() const
    {
        return chiset.any();
    }

    bool is_set(const unsigned position) const
    {
        assert(position < 64);
        return chiset[position];
    }

    bool is_leaf(const unsigned position) const
    {
        assert(position < 64);
        return !inv_leaf[position];
    }

    /*
     * destroy children
     */
    void collapse()
    {
        const unsigned c_amnt { children_amnt() };

        for(unsigned i=0; i<c_amnt; ++i) {
            children[i]->collapse();
        }

        children.clear(c_amnt);
        values.clear(c_amnt);
        chiset.reset();
    }

    /*
     * insert a tree into position of tree
     * position should be result of get_position
     */
    void insert(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children.insert(cpos, new tree<value_type>(), c_amnt);
        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.set(position);
    }

    /*
     * insert a leaf into position of tree
     * position should be result of get_position
     */
    void insert_leaf(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(! is_set(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        values.insert(cpos, value, c_amnt);
        chiset.set(position);
        inv_leaf.reset(position);
    }

    /*
     * removes an item from tree
     * position should be result of get_position
     */
    void remove(const unsigned position)
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos   { get_children_position(position) };
        const unsigned c_amnt { children_amnt() };

        children[cpos]->collapse();
        children.erase(cpos);
        values.erase(cpos);
        chiset.reset(position);
    }

    /*
     * get child node
     * position should be result of get_position
     */
    tree<value_type> * child(const unsigned position) const
    {
        assert(position < 64);
        assert(is_set(position));
        assert(! is_leaf(position));

        const unsigned cpos { get_children_position(position) };

        return children[cpos];
    }

    /*
     * sets node to specific value
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    void set_value(const unsigned position, const value_type value)
    {
        assert(position < 64);
        assert(is_set(position));

        const unsigned cpos { get_children_position(position) };

        values[cpos] = value;
    }

    /*
     * gets value from specific position
     * note: this does not check whether a value has been inserted here yet
     * position should be result of get_position
     */
    value_type get_value(const unsigned position) const
    {
        assert(position < 64);

        const unsigned cpos { get_children_position(position) };

        return values[cpos];
    }

    /************************************************
     *
     * BENCHMARKING CODE
     *
     ***********************************************/

    std::size_t calculate_memory_size() const
    {
        const unsigned c_amnt { children_amnt() };
        const unsigned v_amnt { value_amount() };

        std::size_t size {
              sizeof(chiset)
            + sizeof(inv_leaf)
            + sizeof(values)   + (v_amnt * sizeof(value_type))
            + sizeof(children) + (c_amnt * sizeof(tree<value_type>*))
        };

        for(unsigned i=0; i<c_amnt; ++i) {
            size += children[i]->calculate_memory_size();
        }

        return size;
    }

    std::size_t calculate_children_amnt() const
    {
        std::size_t amount { children_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_children_amnt();
        }

        return amount;
    }

    std::size_t calculate_leaf_amount() const
    {
        std::size_t amount { leaf_amnt() };

        for(unsigned i=0, c_amnt = children_amnt(); i<c_amnt; ++i) {
            amount += children[i]->calculate_leaf_amount();
        }

        return amount;
    }

    void mem_usage_info() const
    {
        const std::size_t memsize { calculate_memory_size() };
        const std::size_t c_amnt  { calculate_children_amnt() };
        const std::size_t l_amnt  { calculate_leaf_amount() };
        const std::size_t v_amnt  { c_amnt + l_amnt };

        std::cout << "total:     " << hckt::render_size(memsize) << std::endl;

        std::cout << "tree-size: " << hckt::render_size(sizeof(tree<value_type>)) << std::endl;
        std::cout << "val-size:  " << hckt::render_size(sizeof(value_type)) << std::endl;

        std::cout << "values:    " << hckt::render_number(v_amnt) << std::endl;
        std::cout << "children:  " << hckt::render_number(c_amnt) << std::endl;
        std::cout << "leaves:    " << hckt::render_number(l_amnt) << std::endl;

        std::cout << "per-val:   " << (static_cast<double>(memsize) / v_amnt) << " B" << std::endl;
        std::cout << "overhead:  " << (static_cast<double>(memsize - (v_amnt * sizeof(value_type))) / v_amnt) << " B" << std::endl;
    }

};

};

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2015, Ming Wen

#ifndef _H_UTIL
#define _H_UTIL

#include "fys.hpp"
#include "json_images.hpp"

using namespace std;
using namespace cv;

namespace fys {

int checkDigit(string str);
string itoa(int idx);
string ftoa(double num);
string btoa(bool var);
bool atob(const char* s);

bool pointsCompXAscend(KeyPoint i, KeyPoint j);
bool pointsCompXDescend(KeyPoint i, KeyPoint j);
bool pointsCompYAscend(KeyPoint i, KeyPoint j);
bool pointsCompYDescend(KeyPoint i, KeyPoint j);

vector<KeyPoint> pointsInRegion(vector<KeyPoint> allPoints, ImageRegion& region);
vector<KeyPoint> pointsInObject(vector<KeyPoint> allPoints, ImageObject& object);
vector<KeyPoint> matchedPoints(vector<KeyPoint> allPoints, vector<DMatch> matches, int type);
ImageRegion locateDenseRegion(vector<KeyPoint> points, double featherRate);

} // namespce fys

#endif // _H_UTIL

<commit_msg>fix a typo in util.hpp<commit_after>// Copyright (c) 2015, Ming Wen

#ifndef _H_UTIL
#define _H_UTIL

#include "fys.hpp"
#include "json_images.hpp"

using namespace std;
using namespace cv;

namespace fys {

int checkDigit(string str);
string itoa(int idx);
string ftoa(double num);
string btoa(bool var);
bool atob(const char* s);

bool pointsCompXAscend(KeyPoint i, KeyPoint j);
bool pointsCompXDescend(KeyPoint i, KeyPoint j);
bool pointsCompYAscend(KeyPoint i, KeyPoint j);
bool pointsCompYDescend(KeyPoint i, KeyPoint j);

vector<KeyPoint> pointsInRegion(vector<KeyPoint> allPoints, ImageRegion& region);
vector<KeyPoint> pointsInObject(vector<KeyPoint> allPoints, ImageObject& object);
vector<KeyPoint> matchedPoints(vector<KeyPoint> allPoints, vector<DMatch> matches, int type);
ImageRegion locateDenseRegion(vector<KeyPoint> points, double featherRate);

} // namespace fys

#endif // _H_UTIL

<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2015 David Robillard <http://drobilla.net/>

  Ingen 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, either version 3 of the License, or any later version.

  Ingen 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 for details.

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

#ifndef INGEN_MODULE_HPP
#define INGEN_MODULE_HPP

#include "ingen/ingen.h"

namespace Glib { class Module; }

namespace Ingen {

class World;

/** A dynamically loaded Ingen module.
 *
 * All components of Ingen reside in one of these.
 * @ingroup IngenShared
 */
class INGEN_API Module {
public:
	Module() : library(nullptr) {}
	virtual ~Module() = default;

	virtual void load(Ingen::World* world) = 0;
	virtual void run(Ingen::World* world) {}

	/** Library implementing this module.
	 *
	 * This is managed by the World and not this class, since closing the library
	 * in this destructor could possibly reference code from the library
	 * afterwards and cause a segfault on exit.
	 */
	Glib::Module* library;

private:
	Module(const Module& noncopyable);
	Module& operator=(const Module& noncopyable);
};

} // namespace Ingen

extern "C" {

/** Prototype for the ingen_module_load() entry point in an ingen module. */
INGEN_API Ingen::Module* ingen_module_load();

}

#endif // INGEN_MODULE_HPP
<commit_msg>Use delete to hide constructors<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2015 David Robillard <http://drobilla.net/>

  Ingen 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, either version 3 of the License, or any later version.

  Ingen 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 for details.

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

#ifndef INGEN_MODULE_HPP
#define INGEN_MODULE_HPP

#include "ingen/ingen.h"

namespace Glib { class Module; }

namespace Ingen {

class World;

/** A dynamically loaded Ingen module.
 *
 * All components of Ingen reside in one of these.
 * @ingroup IngenShared
 */
class INGEN_API Module {
public:
	Module() : library(nullptr) {}
	virtual ~Module() = default;

	virtual void load(Ingen::World* world) = 0;
	virtual void run(Ingen::World* world) {}

	/** Library implementing this module.
	 *
	 * This is managed by the World and not this class, since closing the library
	 * in this destructor could possibly reference code from the library
	 * afterwards and cause a segfault on exit.
	 */
	Glib::Module* library;

private:
	Module(const Module& noncopyable) = delete;
	Module& operator=(const Module& noncopyable) = delete;
};

} // namespace Ingen

extern "C" {

/** Prototype for the ingen_module_load() entry point in an ingen module. */
INGEN_API Ingen::Module* ingen_module_load();

}

#endif // INGEN_MODULE_HPP
<|endoftext|>


<commit_before>#include "Atm_condition.hpp"

Atm_condition & Atm_condition::begin( bool default_state /* = false */ ) {
  const static state_t state_table[] PROGMEM = {
    /*              ON_ENTER    ON_LOOP  ON_EXIT  EVT_ON  EVT_OFF  EVT_TOGGLE EVT_INPUT ELSE */
    /* OFF     */    ACT_OFF,        -1,      -1,     ON,      -1,         ON,      OFF,  -1,
    /* ON      */     ACT_ON,        -1,      -1,     -1,     OFF,        OFF,       ON,  -1,
  };
  Machine::begin( state_table, ELSE );
  _last_state = -1;
  state( default_state ? ON : OFF );
//  cycle();   Causes the condition to become true momentarily
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, stepcb_t callback )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_CALLBACK;
  _comm[idx]._callback = callback;
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, Machine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_MACHINE;
  _comm[idx]._client_machine = &machine;
  _comm[idx]._client_machine_event = event;
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, const char * label, state_t event /* = 0 */ )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_FACTORY;
  _comm[idx]._client_label = label;
  _comm[idx]._client_label_event = event;
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, TinyMachine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_TMACHINE;
  _comm[idx]._client_tmachine = &machine;
  _comm[idx]._client_tmachine_event = event;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, stepcb_t callback )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_CALLBACK;
  _comm[idx]._callback = callback;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, Machine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_MACHINE;
  _comm[idx]._client_machine = &machine;
  _comm[idx]._client_machine_event = event;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, const char * label, state_t event /* = 0 */ )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_FACTORY;
  _comm[idx]._client_label = label;
  _comm[idx]._client_label_event = event;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, TinyMachine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_TMACHINE;
  _comm[idx]._client_tmachine = &machine;
  _comm[idx]._client_tmachine_event = event;
  return *this;
}

Atm_condition & Atm_condition::IF( Machine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '?', machine, relOp, match );
}

Atm_condition & Atm_condition::IF( TinyMachine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '?', machine, relOp, match );
}

Atm_condition & Atm_condition::AND( Machine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '&', machine, relOp, match );
}

Atm_condition & Atm_condition::AND( TinyMachine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '&', machine, relOp, match );
}

Atm_condition & Atm_condition::OR( Machine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '|', machine, relOp, match );
}

Atm_condition & Atm_condition::OR( TinyMachine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '|', machine, relOp, match );
}

Atm_condition & Atm_condition::OP( char logOp, Machine & machine, char relOp = '>', state_t match = 0 ) {
  for ( uint8_t i = 0; i < ATM_CONDITION_OP_MAX; i++ ) { // Fix me off-by-one, should be <!!!
    if ( _op[i]._mode == MODE_NULL ) { // Pick the first free slot
      _op[i]._mode = MODE_MACHINE;
      _op[i]._logop = logOp;
      _op[i]._relop = relOp;
      _op[i]._client_machine = &machine;
      _op[i]._client_machine_event = match;
      break;
    }
  }
  return *this;
}

Atm_condition & Atm_condition::OP( char logOp, TinyMachine & machine, char relOp, state_t match  ) {
  for ( uint8_t i = 0; i < ATM_CONDITION_OP_MAX; i++ ) {
    if ( _op[i]._mode == MODE_NULL ) { // Pick the first free slot
      _op[i]._mode = MODE_TMACHINE;
      _op[i]._logop = logOp;
      _op[i]._relop = relOp;
      _op[i]._client_tmachine = &machine;
      _op[i]._client_tmachine_event = match;
      break;
    }
  }
  return *this;
}

bool Atm_condition::eval_one( uint8_t idx ) {

  if ( _op[idx]._mode == MODE_MACHINE ) {
    state_t machine_state = _op[idx]._client_machine->state();
    switch ( _op[idx]._relop ) {
      case '=' : return machine_state == _op[idx]._client_machine_event;
      case '!' : return machine_state != _op[idx]._client_machine_event;
      case '<' : return machine_state <  _op[idx]._client_machine_event;
      case '>' : return machine_state >  _op[idx]._client_machine_event;
      case '-' : return machine_state <= _op[idx]._client_machine_event;
      case '+' : return machine_state >= _op[idx]._client_machine_event;
    }
  }
  if ( _op[idx]._mode == MODE_TMACHINE ) {
    state_t machine_state = _op[idx]._client_tmachine->state();
    switch ( _op[idx]._relop ) {
      case '=' : return machine_state == _op[idx]._client_tmachine_event;
      case '!' : return machine_state != _op[idx]._client_tmachine_event;
      case '<' : return machine_state <  _op[idx]._client_tmachine_event;
      case '>' : return machine_state >  _op[idx]._client_tmachine_event;
      case '-' : return machine_state <= _op[idx]._client_tmachine_event;
      case '+' : return machine_state >= _op[idx]._client_tmachine_event;
    }
  }
  return false;
}

bool Atm_condition::eval() {

  bool r = eval_one( 0 );
  for ( uint8_t i = 1; i < ATM_CONDITION_OP_MAX; i++ ) {
    if ( _op[i]._mode ) {
      switch ( _op[i]._logop ) {
        case '&' :
          r = r && eval_one( i );
          break;
        case '|' :
          r = r || eval_one( i );
          break;
      }
    }
  }
  return r;
}

int Atm_condition::event( int id ) {
   switch (id ) {
     case EVT_ON :
       return eval();
     case EVT_OFF :
       return !eval();
   }
   return 0;
}

void Atm_condition::comm( Atm_Condition_Comm & c, state_t st ) {

  switch ( c._mode ) {
    case MODE_CALLBACK :
      (*c._callback)( st );
      return;
    case MODE_MACHINE :
      c._client_machine->trigger( c._client_machine_event );
      return;
    case MODE_TMACHINE :
      c._client_tmachine->trigger( c._client_tmachine_event );
      return;
    case MODE_FACTORY:
      factory->trigger( c._client_label, c._client_label_event );
      return;
  }
}

void Atm_condition::action( int id ) {
  switch ( id ) {
    case ACT_OFF :
        comm( _comm[ _last_state == current ? 3 : 1 ], current );
      _last_state = current;
      return;
    case ACT_ON :
      if ( _last_state != -1 )
      comm( _comm[ _last_state == current ? 2 : 0 ], current );
      _last_state = current;
      return;
   }
}

Atm_condition & Atm_condition::trace( Stream & stream ) {
  Machine::setTrace( &stream, atm_serial_debug::trace,
    "EVT_ON\0EVT_OFF\0EVT_TOGGLE\0EVT_INPUT\0ELSE\0OFF\0ON" );
  return *this;
}

<commit_msg>Removed comment<commit_after>#include "Atm_condition.hpp"

Atm_condition & Atm_condition::begin( bool default_state /* = false */ ) {
  const static state_t state_table[] PROGMEM = {
    /*              ON_ENTER    ON_LOOP  ON_EXIT  EVT_ON  EVT_OFF  EVT_TOGGLE EVT_INPUT ELSE */
    /* OFF     */    ACT_OFF,        -1,      -1,     ON,      -1,         ON,      OFF,  -1,
    /* ON      */     ACT_ON,        -1,      -1,     -1,     OFF,        OFF,       ON,  -1,
  };
  Machine::begin( state_table, ELSE );
  _last_state = -1;
  state( default_state ? ON : OFF );
//  cycle();   Causes the condition to become true momentarily
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, stepcb_t callback )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_CALLBACK;
  _comm[idx]._callback = callback;
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, Machine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_MACHINE;
  _comm[idx]._client_machine = &machine;
  _comm[idx]._client_machine_event = event;
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, const char * label, state_t event /* = 0 */ )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_FACTORY;
  _comm[idx]._client_label = label;
  _comm[idx]._client_label_event = event;
  return *this;
}

Atm_condition & Atm_condition::onFlip( bool st, TinyMachine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 0 : 1;
  _comm[idx]._mode = MODE_TMACHINE;
  _comm[idx]._client_tmachine = &machine;
  _comm[idx]._client_tmachine_event = event;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, stepcb_t callback )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_CALLBACK;
  _comm[idx]._callback = callback;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, Machine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_MACHINE;
  _comm[idx]._client_machine = &machine;
  _comm[idx]._client_machine_event = event;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, const char * label, state_t event /* = 0 */ )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_FACTORY;
  _comm[idx]._client_label = label;
  _comm[idx]._client_label_event = event;
  return *this;
}

Atm_condition & Atm_condition::onInput( bool st, TinyMachine & machine, state_t event /* = 0 */ )
{
  short idx = st ? 2 : 3;
  _comm[idx]._mode = MODE_TMACHINE;
  _comm[idx]._client_tmachine = &machine;
  _comm[idx]._client_tmachine_event = event;
  return *this;
}

Atm_condition & Atm_condition::IF( Machine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '?', machine, relOp, match );
}

Atm_condition & Atm_condition::IF( TinyMachine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '?', machine, relOp, match );
}

Atm_condition & Atm_condition::AND( Machine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '&', machine, relOp, match );
}

Atm_condition & Atm_condition::AND( TinyMachine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '&', machine, relOp, match );
}

Atm_condition & Atm_condition::OR( Machine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '|', machine, relOp, match );
}

Atm_condition & Atm_condition::OR( TinyMachine & machine, char relOp /* = '>' */, state_t match /* = 0 */ ) {
  return OP( '|', machine, relOp, match );
}

Atm_condition & Atm_condition::OP( char logOp, Machine & machine, char relOp = '>', state_t match = 0 ) {
  for ( uint8_t i = 0; i < ATM_CONDITION_OP_MAX; i++ ) {
    if ( _op[i]._mode == MODE_NULL ) { // Pick the first free slot
      _op[i]._mode = MODE_MACHINE;
      _op[i]._logop = logOp;
      _op[i]._relop = relOp;
      _op[i]._client_machine = &machine;
      _op[i]._client_machine_event = match;
      break;
    }
  }
  return *this;
}

Atm_condition & Atm_condition::OP( char logOp, TinyMachine & machine, char relOp, state_t match  ) {
  for ( uint8_t i = 0; i < ATM_CONDITION_OP_MAX; i++ ) {
    if ( _op[i]._mode == MODE_NULL ) { // Pick the first free slot
      _op[i]._mode = MODE_TMACHINE;
      _op[i]._logop = logOp;
      _op[i]._relop = relOp;
      _op[i]._client_tmachine = &machine;
      _op[i]._client_tmachine_event = match;
      break;
    }
  }
  return *this;
}

bool Atm_condition::eval_one( uint8_t idx ) {

  if ( _op[idx]._mode == MODE_MACHINE ) {
    state_t machine_state = _op[idx]._client_machine->state();
    switch ( _op[idx]._relop ) {
      case '=' : return machine_state == _op[idx]._client_machine_event;
      case '!' : return machine_state != _op[idx]._client_machine_event;
      case '<' : return machine_state <  _op[idx]._client_machine_event;
      case '>' : return machine_state >  _op[idx]._client_machine_event;
      case '-' : return machine_state <= _op[idx]._client_machine_event;
      case '+' : return machine_state >= _op[idx]._client_machine_event;
    }
  }
  if ( _op[idx]._mode == MODE_TMACHINE ) {
    state_t machine_state = _op[idx]._client_tmachine->state();
    switch ( _op[idx]._relop ) {
      case '=' : return machine_state == _op[idx]._client_tmachine_event;
      case '!' : return machine_state != _op[idx]._client_tmachine_event;
      case '<' : return machine_state <  _op[idx]._client_tmachine_event;
      case '>' : return machine_state >  _op[idx]._client_tmachine_event;
      case '-' : return machine_state <= _op[idx]._client_tmachine_event;
      case '+' : return machine_state >= _op[idx]._client_tmachine_event;
    }
  }
  return false;
}

bool Atm_condition::eval() {

  bool r = eval_one( 0 );
  for ( uint8_t i = 1; i < ATM_CONDITION_OP_MAX; i++ ) {
    if ( _op[i]._mode ) {
      switch ( _op[i]._logop ) {
        case '&' :
          r = r && eval_one( i );
          break;
        case '|' :
          r = r || eval_one( i );
          break;
      }
    }
  }
  return r;
}

int Atm_condition::event( int id ) {
   switch (id ) {
     case EVT_ON :
       return eval();
     case EVT_OFF :
       return !eval();
   }
   return 0;
}

void Atm_condition::comm( Atm_Condition_Comm & c, state_t st ) {

  switch ( c._mode ) {
    case MODE_CALLBACK :
      (*c._callback)( st );
      return;
    case MODE_MACHINE :
      c._client_machine->trigger( c._client_machine_event );
      return;
    case MODE_TMACHINE :
      c._client_tmachine->trigger( c._client_tmachine_event );
      return;
    case MODE_FACTORY:
      factory->trigger( c._client_label, c._client_label_event );
      return;
  }
}

void Atm_condition::action( int id ) {
  switch ( id ) {
    case ACT_OFF :
        comm( _comm[ _last_state == current ? 3 : 1 ], current );
      _last_state = current;
      return;
    case ACT_ON :
      if ( _last_state != -1 )
      comm( _comm[ _last_state == current ? 2 : 0 ], current );
      _last_state = current;
      return;
   }
}

Atm_condition & Atm_condition::trace( Stream & stream ) {
  Machine::setTrace( &stream, atm_serial_debug::trace,
    "EVT_ON\0EVT_OFF\0EVT_TOGGLE\0EVT_INPUT\0ELSE\0OFF\0ON" );
  return *this;
}

<|endoftext|>