<commit_before>/*
    This file is part of Akregator.

    Copyright (C) 2005 Frank Osterfeld <osterfeld@kde.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "actionmanager.h"
#include "browserframe.h"
#include "browserframe_p.h"
#include "openurlrequest.h"

#include <QAction>
#include <QGridLayout>
#include <QList>
#include <QPoint>
#include <QString>
#include <QWidget>

#include <kaction.h>
#include <kdebug.h>
#include <klibloader.h>
#include <kmenu.h>
#include <kmimetypetrader.h>
#include <ktoolbarpopupaction.h>
#include <kurl.h>
#include <kxmlguiclient.h>
#include <kparts/browserextension.h>
#include <kparts/part.h>

namespace Akregator {

BrowserFrame::BrowserFrame(QWidget* parent) : Frame(parent)
{
    d = new BrowserFramePrivate(this);

    d->part = 0;
    d->extension = 0;
    d->lockHistory = false;
    d->isLoading = false;
    setRemovable(true);
    d->current = d->history.end();

    d->layout = new QGridLayout( this );
    d->layout->setMargin( 0 );
}

BrowserFrame::~BrowserFrame()
{
    if (d->part)
        d->part->deleteLater();
    delete d;
    d = 0;
}

KUrl BrowserFrame::url() const
{
    return d->part ? d->part->url() : KUrl();
}

bool BrowserFrame::canGoForward() const
{
    return !d->history.isEmpty() && d->current != d->history.end()-1 && d->current != d->history.end();
}

bool BrowserFrame::canGoBack() const
{
    return !d->history.isEmpty() && d->current != d->history.begin();
}

void BrowserFrame::slotOpenUrlNotify()
{
    // TODO: inform the world that a new url was opened
}

void BrowserFrame::slotSetLocationBarUrl(const QString& /*url*/)
{
    // TODO: use this to update URLs for dragging (like tab drag etc.)
}

void BrowserFrame::slotSetIconUrl(const KUrl& /*url*/)
{
}

void BrowserFrame::slotSpeedProgress(int /*bytesPerSecond*/)
{
}

void BrowserFrame::slotPopupMenu(
                   const QPoint& global,
                   const KUrl& url,
                   mode_t mode,
                   const KParts::OpenUrlArguments& args,
                   const KParts::BrowserArguments& browserArgs,
                   KParts::BrowserExtension::PopupFlags flags)
{
    const bool showReload = (flags & KParts::BrowserExtension::ShowReload) != 0;
    const bool showNavigationItems = (flags & KParts::BrowserExtension::ShowNavigationItems) != 0;
    const bool isLink = (flags & KParts::BrowserExtension:: IsLink) != 0;
    const bool isSelection = (flags & KParts::BrowserExtension::ShowTextSelectionItems) != 0;

    bool isFirst = true;

    KMenu popup(d->part->widget());

    /*
    if (showNavigationItems)
    {
        popup.addAction(ActionManager::getInstance()->action("browser_back"));
        popup.addAction(ActionManager::getInstance()->action("browser_forward"));
        isFirst = false;
    }
    if (showReload)
    {
        popup.addAction(ActionManager::getInstance()->action("browser_reload"));
        isFirst = false;
    }

    if (isLink)
    {
        if (!isFirst)
            popup.addSeparator();
        // open link in new tab
        // ext browser
        popup.addSeparator();
        popup.addAction(d->part->action("savelinkas"));
        // save link as
        // copy link address
        isFirst = false;
    }

    if (isSelection)
    {
        if (!isFirst)
            popup.addSeparator();

        popup.addAction(d->part->action("copy"));
        isFirst = false;
    }
    */
    popup.exec(global);
}

void BrowserFrame::slotOpenUrlRequestDelayed(const KUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& browserArgs)
{
    OpenUrlRequest req;

    req.setFrameId(id());
    req.setUrl(url);
    req.setArgs(args);
    req.setBrowserArgs(browserArgs);

    emit signalOpenUrlRequest(req);
}

void BrowserFrame::slotCreateNewWindow(const KUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& browserArgs)
{
    OpenUrlRequest req;
    req.setFrameId(id());
    req.setUrl(url);
    req.setArgs(args);
    req.setBrowserArgs(browserArgs);
    req.setOptions(OpenUrlRequest::NewTab);

    emit signalOpenUrlRequest(req);
}

void BrowserFrame::slotCreateNewWindow(const KUrl& url,
                                       const KParts::OpenUrlArguments& args,
                                       const KParts::BrowserArguments& browserArgs,
                                       const KParts::WindowArgs& /*windowArgs*/,
                                       KParts::ReadOnlyPart** part)
{
    OpenUrlRequest req;
    req.setFrameId(id());
    req.setUrl(url);
    req.setArgs(args);
    req.setBrowserArgs(browserArgs);
    req.setOptions(OpenUrlRequest::NewTab);

    emit signalOpenUrlRequest(req);
    *part = req.part();
}

bool BrowserFrame::openUrl(const OpenUrlRequest& request)
{
    QString serviceType = request.args().mimeType();

    if (serviceType.isEmpty())
        return false;

    d->updateHistoryEntry();

    if (d->loadPartForMimetype(serviceType))
    {
        if (d->part)
        {
            d->part->setArguments(request.args());
        }
        bool res = false;

        if (request.url().isValid())
            res = d->part->openUrl(request.url());

        if (res)
        {
            d->appendHistoryEntry(request.url());
            d->updateHistoryEntry();
        }

        return res;
    }
    else
    {
            // TODO: show open|save|cancel dialog

    }

    return false; // TODO: is this correct?
}

KParts::ReadOnlyPart* BrowserFrame::part() const
{
    return d->part;
}

void BrowserFrame::slotHistoryBackAboutToShow()
{
    QAction* ba = ActionManager::getInstance()->action("browser_back");
    QMenu* popup = static_cast<KToolBarPopupAction*>(ba)->menu();
    popup->clear();

    if (!canGoBack())
        return;

    QList<BrowserFramePrivate::HistoryEntry>::Iterator it = d->current-1;

    int i = 0;
    while( i < 10)
    {
        if ( it == d->history.begin() )
        {
            popup->addAction(new BrowserFramePrivate::HistoryAction(it, popup, d));
            return;
        }

        popup->addAction(new BrowserFramePrivate::HistoryAction(it, popup, d));
        ++i;
        --it;
    }
}

void BrowserFrame::slotHistoryForwardAboutToShow()
{
    QAction* fw = ActionManager::getInstance()->action("browser_forward");
    QMenu* popup = static_cast<KToolBarPopupAction*>(fw)->menu();
    popup->clear();

    if (!canGoForward())
        return;

    QList<BrowserFramePrivate::HistoryEntry>::Iterator it = d->current+1;

    int i = 0;
    while( i < 10)
    {
        if ( it == d->history.end()-1 )
        {
            popup->addAction( new BrowserFramePrivate::HistoryAction(it, popup, d));
            return;
        }

        popup->addAction(new BrowserFramePrivate::HistoryAction(it, popup, d));
        ++i;
        ++it;
    }
}

void BrowserFrame::slotHistoryForward()
{
    if (canGoForward())
        d->restoreHistoryEntry(d->current+1);
}

void BrowserFrame::slotHistoryBack()
{
    if (canGoBack())
        d->restoreHistoryEntry(d->current-1);
}

void BrowserFrame::slotReload()
{
    // TODO
    //d->lockHistory = true;
    //openUrl(d->url, d->mimetype); // this s
    //d->lockHistory = false;
}

void BrowserFrame::slotStop()
{
    if (d->part)
        d->part->closeUrl();
    Frame::slotStop();

}

void BrowserFrame::slotPaletteOrFontChanged()
{
}

bool BrowserFrame::isReloadable() const
{
    return false; // TODO
}

bool BrowserFrame::isLoading() const
{
    return d->isLoading;
}

} // namespace Akregator

#include "browserframe.moc"
<commit_msg>do not crash when part is null<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2005 Frank Osterfeld <osterfeld@kde.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "actionmanager.h"
#include "browserframe.h"
#include "browserframe_p.h"
#include "openurlrequest.h"

#include <QAction>
#include <QGridLayout>
#include <QList>
#include <QPoint>
#include <QString>
#include <QWidget>

#include <kaction.h>
#include <kdebug.h>
#include <klibloader.h>
#include <kmenu.h>
#include <kmimetypetrader.h>
#include <ktoolbarpopupaction.h>
#include <kurl.h>
#include <kxmlguiclient.h>
#include <kparts/browserextension.h>
#include <kparts/part.h>

namespace Akregator {

BrowserFrame::BrowserFrame(QWidget* parent) : Frame(parent)
{
    d = new BrowserFramePrivate(this);

    d->part = 0;
    d->extension = 0;
    d->lockHistory = false;
    d->isLoading = false;
    setRemovable(true);
    d->current = d->history.end();

    d->layout = new QGridLayout( this );
    d->layout->setMargin( 0 );
}

BrowserFrame::~BrowserFrame()
{
    if (d->part)
        d->part->deleteLater();
    delete d;
    d = 0;
}

KUrl BrowserFrame::url() const
{
    return d->part ? d->part->url() : KUrl();
}

bool BrowserFrame::canGoForward() const
{
    return !d->history.isEmpty() && d->current != d->history.end()-1 && d->current != d->history.end();
}

bool BrowserFrame::canGoBack() const
{
    return !d->history.isEmpty() && d->current != d->history.begin();
}

void BrowserFrame::slotOpenUrlNotify()
{
    // TODO: inform the world that a new url was opened
}

void BrowserFrame::slotSetLocationBarUrl(const QString& /*url*/)
{
    // TODO: use this to update URLs for dragging (like tab drag etc.)
}

void BrowserFrame::slotSetIconUrl(const KUrl& /*url*/)
{
}

void BrowserFrame::slotSpeedProgress(int /*bytesPerSecond*/)
{
}

void BrowserFrame::slotPopupMenu(
                   const QPoint& global,
                   const KUrl& url,
                   mode_t mode,
                   const KParts::OpenUrlArguments& args,
                   const KParts::BrowserArguments& browserArgs,
                   KParts::BrowserExtension::PopupFlags flags)
{
    const bool showReload = (flags & KParts::BrowserExtension::ShowReload) != 0;
    const bool showNavigationItems = (flags & KParts::BrowserExtension::ShowNavigationItems) != 0;
    const bool isLink = (flags & KParts::BrowserExtension:: IsLink) != 0;
    const bool isSelection = (flags & KParts::BrowserExtension::ShowTextSelectionItems) != 0;

    bool isFirst = true;

    KMenu popup(d->part->widget());

    /*
    if (showNavigationItems)
    {
        popup.addAction(ActionManager::getInstance()->action("browser_back"));
        popup.addAction(ActionManager::getInstance()->action("browser_forward"));
        isFirst = false;
    }
    if (showReload)
    {
        popup.addAction(ActionManager::getInstance()->action("browser_reload"));
        isFirst = false;
    }

    if (isLink)
    {
        if (!isFirst)
            popup.addSeparator();
        // open link in new tab
        // ext browser
        popup.addSeparator();
        popup.addAction(d->part->action("savelinkas"));
        // save link as
        // copy link address
        isFirst = false;
    }

    if (isSelection)
    {
        if (!isFirst)
            popup.addSeparator();

        popup.addAction(d->part->action("copy"));
        isFirst = false;
    }
    */
    popup.exec(global);
}

void BrowserFrame::slotOpenUrlRequestDelayed(const KUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& browserArgs)
{
    OpenUrlRequest req;

    req.setFrameId(id());
    req.setUrl(url);
    req.setArgs(args);
    req.setBrowserArgs(browserArgs);

    emit signalOpenUrlRequest(req);
}

void BrowserFrame::slotCreateNewWindow(const KUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& browserArgs)
{
    OpenUrlRequest req;
    req.setFrameId(id());
    req.setUrl(url);
    req.setArgs(args);
    req.setBrowserArgs(browserArgs);
    req.setOptions(OpenUrlRequest::NewTab);

    emit signalOpenUrlRequest(req);
}

void BrowserFrame::slotCreateNewWindow(const KUrl& url,
                                       const KParts::OpenUrlArguments& args,
                                       const KParts::BrowserArguments& browserArgs,
                                       const KParts::WindowArgs& /*windowArgs*/,
                                       KParts::ReadOnlyPart** part)
{
    OpenUrlRequest req;
    req.setFrameId(id());
    req.setUrl(url);
    req.setArgs(args);
    req.setBrowserArgs(browserArgs);
    req.setOptions(OpenUrlRequest::NewTab);

    emit signalOpenUrlRequest(req);
    if ( part )
        *part = req.part();
}

bool BrowserFrame::openUrl(const OpenUrlRequest& request)
{
    QString serviceType = request.args().mimeType();

    if (serviceType.isEmpty())
        return false;

    d->updateHistoryEntry();

    if (d->loadPartForMimetype(serviceType))
    {
        if (d->part)
        {
            d->part->setArguments(request.args());
        }
        bool res = false;

        if (request.url().isValid())
            res = d->part->openUrl(request.url());

        if (res)
        {
            d->appendHistoryEntry(request.url());
            d->updateHistoryEntry();
        }

        return res;
    }
    else
    {
            // TODO: show open|save|cancel dialog

    }

    return false; // TODO: is this correct?
}

KParts::ReadOnlyPart* BrowserFrame::part() const
{
    return d->part;
}

void BrowserFrame::slotHistoryBackAboutToShow()
{
    QAction* ba = ActionManager::getInstance()->action("browser_back");
    QMenu* popup = static_cast<KToolBarPopupAction*>(ba)->menu();
    popup->clear();

    if (!canGoBack())
        return;

    QList<BrowserFramePrivate::HistoryEntry>::Iterator it = d->current-1;

    int i = 0;
    while( i < 10)
    {
        if ( it == d->history.begin() )
        {
            popup->addAction(new BrowserFramePrivate::HistoryAction(it, popup, d));
            return;
        }

        popup->addAction(new BrowserFramePrivate::HistoryAction(it, popup, d));
        ++i;
        --it;
    }
}

void BrowserFrame::slotHistoryForwardAboutToShow()
{
    QAction* fw = ActionManager::getInstance()->action("browser_forward");
    QMenu* popup = static_cast<KToolBarPopupAction*>(fw)->menu();
    popup->clear();

    if (!canGoForward())
        return;

    QList<BrowserFramePrivate::HistoryEntry>::Iterator it = d->current+1;

    int i = 0;
    while( i < 10)
    {
        if ( it == d->history.end()-1 )
        {
            popup->addAction( new BrowserFramePrivate::HistoryAction(it, popup, d));
            return;
        }

        popup->addAction(new BrowserFramePrivate::HistoryAction(it, popup, d));
        ++i;
        ++it;
    }
}

void BrowserFrame::slotHistoryForward()
{
    if (canGoForward())
        d->restoreHistoryEntry(d->current+1);
}

void BrowserFrame::slotHistoryBack()
{
    if (canGoBack())
        d->restoreHistoryEntry(d->current-1);
}

void BrowserFrame::slotReload()
{
    // TODO
    //d->lockHistory = true;
    //openUrl(d->url, d->mimetype); // this s
    //d->lockHistory = false;
}

void BrowserFrame::slotStop()
{
    if (d->part)
        d->part->closeUrl();
    Frame::slotStop();

}

void BrowserFrame::slotPaletteOrFontChanged()
{
}

bool BrowserFrame::isReloadable() const
{
    return false; // TODO
}

bool BrowserFrame::isLoading() const
{
    return d->isLoading;
}

} // namespace Akregator

#include "browserframe.moc"
<|endoftext|>


<commit_before>// Base class for property controlled subsystems
//
// Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA

#include "PropertyBasedMgr.hxx"

#include <boost/foreach.hpp>

#include <stdexcept>
#include <string>

namespace simgear
{

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::init()
  {
    _props->addChangeListener(this);
    _props->fireCreatedRecursive();
  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::shutdown()
  {
    _props->removeChangeListener(this);
  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::update(double delta_time_sec)
  {
    for( size_t i = 0; i < _elements.size(); ++i )
      if( _elements[i] )
        _elements[i]->update(delta_time_sec);
  }

  //----------------------------------------------------------------------------
  PropertyBasedElementPtr
  PropertyBasedMgr::createElement(const std::string& name)
  {
    SGPropertyNode* node = _props->addChild(_name_elements, 0, false);
    if( !name.empty() )
      node->setStringValue("name", name);

    return getElement( node->getIndex() );
  }

  //----------------------------------------------------------------------------
  PropertyBasedElementPtr PropertyBasedMgr::getElement(size_t index) const
  {
    if( index >= _elements.size() )
      return PropertyBasedElementPtr();

    return _elements[index];
  }

  //----------------------------------------------------------------------------
  PropertyBasedElementPtr
  PropertyBasedMgr::getElement(const std::string& name) const
  {
    if( name.empty() )
      return PropertyBasedElementPtr();

    BOOST_FOREACH(PropertyBasedElementPtr el, _elements)
      if( el->getProps()->getStringValue("name") == name )
        return el;

    return PropertyBasedElementPtr();
  }

  //----------------------------------------------------------------------------
  const SGPropertyNode* PropertyBasedMgr::getPropertyRoot() const
  {
    return _props;
  }

  //----------------------------------------------------------------------------
  PropertyBasedMgr::PropertyBasedMgr( SGPropertyNode_ptr props,
                                      const std::string& name_elements,
                                      ElementFactory element_factory ):
    _props( props ),
    _name_elements( name_elements ),
    _element_factory( element_factory )
  {

  }

  //----------------------------------------------------------------------------
  PropertyBasedMgr::~PropertyBasedMgr()
  {

  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::childAdded( SGPropertyNode * parent,
                                     SGPropertyNode * child )
  {
    if( parent != _props || child->getNameString() != _name_elements )
      return;

    size_t index = child->getIndex();

    if( index >= _elements.size() )
    {
      if( index > _elements.size() )
        SG_LOG
        (
          SG_GENERAL,
          SG_WARN,
          "Skipping unused " << _name_elements << " slot(s)!"
        );

      _elements.resize(index + 1);
    }
    else if( _elements[index] )
    {
      SG_LOG
      (
        SG_GENERAL,
        SG_WARN,
        _name_elements << "[" << index << "] already exists!"
      );

      // Give anything holding a reference to this element to release it
      _elements[index]->onDestroy();
    }

    PropertyBasedElementPtr el = _element_factory(child);
    el->setSelf( el );
    _elements[index] = el;
    elementCreated( el );
  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::childRemoved( SGPropertyNode * parent,
                                       SGPropertyNode * child )
  {
    if( parent != _props )
      return child->fireChildrenRemovedRecursive();
    else if( child->getNameString() != _name_elements )
      return;

    size_t index = child->getIndex();

    if( index >= _elements.size() )
      SG_LOG
      (
        SG_GENERAL,
        SG_WARN,
        "can't removed unknown " << _name_elements << "[" << index << "]!"
      );
    else
    {
      // remove the element...
      _elements[index]->onDestroy();
      _elements[index].reset();
    }
  }

} // namespace simgear
<commit_msg>Canvas: clear elements in shutdown()<commit_after>// Base class for property controlled subsystems
//
// Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA

#include "PropertyBasedMgr.hxx"

#include <boost/foreach.hpp>

#include <stdexcept>
#include <string>

namespace simgear
{

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::init()
  {
    _props->addChangeListener(this);
    _props->fireCreatedRecursive();
  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::shutdown()
  {
    _props->removeChangeListener(this);
    _elements.clear();
  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::update(double delta_time_sec)
  {
    for( size_t i = 0; i < _elements.size(); ++i )
      if( _elements[i] )
        _elements[i]->update(delta_time_sec);
  }

  //----------------------------------------------------------------------------
  PropertyBasedElementPtr
  PropertyBasedMgr::createElement(const std::string& name)
  {
    SGPropertyNode* node = _props->addChild(_name_elements, 0, false);
    if( !name.empty() )
      node->setStringValue("name", name);

    return getElement( node->getIndex() );
  }

  //----------------------------------------------------------------------------
  PropertyBasedElementPtr PropertyBasedMgr::getElement(size_t index) const
  {
    if( index >= _elements.size() )
      return PropertyBasedElementPtr();

    return _elements[index];
  }

  //----------------------------------------------------------------------------
  PropertyBasedElementPtr
  PropertyBasedMgr::getElement(const std::string& name) const
  {
    if( name.empty() )
      return PropertyBasedElementPtr();

    BOOST_FOREACH(PropertyBasedElementPtr el, _elements)
      if( el->getProps()->getStringValue("name") == name )
        return el;

    return PropertyBasedElementPtr();
  }

  //----------------------------------------------------------------------------
  const SGPropertyNode* PropertyBasedMgr::getPropertyRoot() const
  {
    return _props;
  }

  //----------------------------------------------------------------------------
  PropertyBasedMgr::PropertyBasedMgr( SGPropertyNode_ptr props,
                                      const std::string& name_elements,
                                      ElementFactory element_factory ):
    _props( props ),
    _name_elements( name_elements ),
    _element_factory( element_factory )
  {

  }

  //----------------------------------------------------------------------------
  PropertyBasedMgr::~PropertyBasedMgr()
  {

  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::childAdded( SGPropertyNode * parent,
                                     SGPropertyNode * child )
  {
    if( parent != _props || child->getNameString() != _name_elements )
      return;

    size_t index = child->getIndex();

    if( index >= _elements.size() )
    {
      if( index > _elements.size() )
        SG_LOG
        (
          SG_GENERAL,
          SG_WARN,
          "Skipping unused " << _name_elements << " slot(s)!"
        );

      _elements.resize(index + 1);
    }
    else if( _elements[index] )
    {
      SG_LOG
      (
        SG_GENERAL,
        SG_WARN,
        _name_elements << "[" << index << "] already exists!"
      );

      // Give anything holding a reference to this element to release it
      _elements[index]->onDestroy();
    }

    PropertyBasedElementPtr el = _element_factory(child);
    el->setSelf( el );
    _elements[index] = el;
    elementCreated( el );
  }

  //----------------------------------------------------------------------------
  void PropertyBasedMgr::childRemoved( SGPropertyNode * parent,
                                       SGPropertyNode * child )
  {
    if( parent != _props )
      return child->fireChildrenRemovedRecursive();
    else if( child->getNameString() != _name_elements )
      return;

    size_t index = child->getIndex();

    if( index >= _elements.size() )
      SG_LOG
      (
        SG_GENERAL,
        SG_WARN,
        "can't removed unknown " << _name_elements << "[" << index << "]!"
      );
    else
    {
      // remove the element...
      _elements[index]->onDestroy();
      _elements[index].reset();
    }
  }

} // namespace simgear
<|endoftext|>


<commit_before>
#include <boost/asio.hpp>

#include "vtrc-protocol-layer.h"
#include "vtrc-connection-iface.h"

#include "vtrc-common/vtrc-monotonic-timer.h"
#include "vtrc-common/vtrc-data-queue.h"
#include "vtrc-common/vtrc-hasher-iface.h"
#include "vtrc-common/vtrc-hasher-impls.h"
#include "vtrc-common/vtrc-transformer-iface.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"

namespace vtrc { namespace server {

    namespace {
        static const size_t maximum_message_length = 1024 * 1024;
    }

    namespace data_queue = common::data_queue;

    struct protocol_layer::protocol_layer_impl {

        connection_iface *connection_;
        protocol_layer   *parent_;
        boost::shared_ptr<common::hasher_iface>      hasher_;
        boost::shared_ptr<common::transformer_iface> transformer_;
        common::data_queue::queue_base_sptr          queue_;

        protocol_layer_impl( connection_iface *c )
            :connection_(c)
            ,hasher_(common::hasher::fake::create( ))
            ,transformer_(common::transformers::none::create( ))
            ,queue_(data_queue::varint::create_parser(maximum_message_length))
        {

        }

        void init( )
        {
            vtrc_auth::init_protocol hello_mess;
            hello_mess.set_hello_message( "Tervetuloa!" );

            hello_mess.add_hash_supported( vtrc_auth::HASH_NONE );
            hello_mess.add_hash_supported( vtrc_auth::HASH_SHA2_256 );

            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_NONE );
            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_ERSEEFOR );

            std::string data(hello_mess.SerializeAsString( ));
            std::string result(queue_->pack_size( data.size( ) ));

            result.append( hasher_->get_data_hash( data.c_str( ),
                                                   data.size( ) ) );
            result.append( data.begin( ), data.end( ) );

            transformer_->transform_data( data.empty( ) ? NULL : &data[0],
                                          data.size( ) );

            connection_->write( data.c_str( ), data.size( ) );
        }

        void process_data( const char *data, size_t length )
        {
            if( length > 0 ) {
                std::string next_data(data, data + length);
                transformer_->revert_data( &next_data[0],
                                           next_data.size( ) );
                queue_->append( &next_data[0], next_data.size( ));
                queue_->process( );
            }
        }
    };

    protocol_layer::protocol_layer( connection_iface *connection )
        :impl_(new protocol_layer_impl(connection))
    {
        impl_->parent_ = this;
    }

    protocol_layer::~protocol_layer( )
    {
        delete impl_;
    }

    void protocol_layer::init( )
    {
        impl_->init( );
    }

    void protocol_layer::process_data( const char *data, size_t length )
    {
        impl_->process_data( data, length );
    }

}}

<commit_msg>protocol<commit_after>
#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

#include "vtrc-protocol-layer.h"
#include "vtrc-connection-iface.h"

#include "vtrc-common/vtrc-monotonic-timer.h"
#include "vtrc-common/vtrc-data-queue.h"
#include "vtrc-common/vtrc-hasher-iface.h"
#include "vtrc-common/vtrc-hasher-impls.h"
#include "vtrc-common/vtrc-transformer-iface.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"

namespace vtrc { namespace server {

    namespace {
        static const size_t maximum_message_length = 1024 * 1024;
        enum init_stage_enum {
             stage_begin             = 1
            ,stage_client_select     = 2
            ,stage_client_ready      = 3
        };
    }

    namespace data_queue = common::data_queue;

    struct protocol_layer::protocol_layer_impl {

        typedef protocol_layer_impl this_type;

        connection_iface *connection_;
        protocol_layer   *parent_;
        boost::shared_ptr<common::hasher_iface>      hasher_;
        boost::shared_ptr<common::transformer_iface> transformer_;
        common::data_queue::queue_base_sptr          queue_;
        init_stage_enum                              init_stages_;

        typedef boost::function<void (void)> stage_function_type;
        stage_function_type  stage_function_;

        protocol_layer_impl( connection_iface *c )
            :connection_(c)
            ,hasher_(common::hasher::fake::create( ))
            ,transformer_(common::transformers::none::create( ))
            ,queue_(data_queue::varint::create_parser(maximum_message_length))
            ,init_stages_(stage_begin)
        {
            stage_function_ =
                    boost::bind( &this_type::on_client_selection, this );
        }

        void on_timer( boost::system::error_code const &error )
        {

        }

        void on_client_selection( )
        {

        }

        void on_ready( )
        {

        }

        void init( )
        {
            vtrc_auth::init_protocol hello_mess;
            hello_mess.set_hello_message( "Tervetuloa!" );

            hello_mess.add_hash_supported( vtrc_auth::HASH_NONE );
            hello_mess.add_hash_supported( vtrc_auth::HASH_SHA2_256 );

            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_NONE );
            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_ERSEEFOR );

            std::string data(hello_mess.SerializeAsString( ));
            std::string result(queue_->pack_size( data.size( ) ));

            result.append( hasher_->get_data_hash( data.c_str( ),
                                                   data.size( ) ) );
            result.append( data.begin( ), data.end( ) );

            transformer_->transform_data( data.empty( ) ? NULL : &data[0],
                                          data.size( ) );

            connection_->write( data.c_str( ), data.size( ) );
        }

        void process_data( const char *data, size_t length )
        {
            if( length > 0 ) {
                std::string next_data(data, data + length);
                transformer_->revert_data( &next_data[0],
                                           next_data.size( ) );
                queue_->append( &next_data[0], next_data.size( ));
                queue_->process( );
                stage_function_( );
            }
        }
    };

    protocol_layer::protocol_layer( connection_iface *connection )
        :impl_(new protocol_layer_impl(connection))
    {
        impl_->parent_ = this;
    }

    protocol_layer::~protocol_layer( )
    {
        delete impl_;
    }

    void protocol_layer::init( )
    {
        impl_->init( );
    }

    void protocol_layer::process_data( const char *data, size_t length )
    {
        impl_->process_data( data, length );
    }

}}

<|endoftext|>


<commit_before>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * 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.
 */

#include "texture_manager.hpp"
#include "device.hpp"
#include "stb_image.h"
#include "memory_mapped_texture.hpp"
#include "texture_files.hpp"

#ifdef GRANITE_VULKAN_MT
#include "thread_group.hpp"
#include "thread_id.hpp"
#endif

using namespace std;

namespace Vulkan
{
bool Texture::init_texture()
{
	if (!path.empty())
		return init();
	else
		return true;
}

Texture::Texture(Device *device_, const std::string &path_, VkFormat format_, const VkComponentMapping &swizzle_)
	: VolatileSource(path_), device(device_), format(format_), swizzle(swizzle_)
{
}

Texture::Texture(Device *device_)
	: device(device_), format(VK_FORMAT_UNDEFINED)
{
}

void Texture::set_path(const std::string &path_)
{
	path = path_;
}

void Texture::update(std::unique_ptr<Granite::File> file)
{
	auto *f = file.release();
	auto work = [f, this]() {
#if defined(GRANITE_VULKAN_MT) && defined(VULKAN_DEBUG)
		LOGI("Loading texture in thread index: %u\n", get_current_thread_index());
#endif
		unique_ptr<Granite::File> updated_file{f};
		auto size = updated_file->get_size();
		void *mapped = updated_file->map();
		if (size && mapped)
		{
			if (Granite::SceneFormats::MemoryMappedTexture::is_header(mapped, size))
				update_gtx(move(updated_file), mapped);
			else
				update_other(mapped, size);
			device->get_texture_manager().notify_updated_texture(path, *this);
		}
		else
		{
			LOGE("Failed to map texture file ...\n");
			update_checkerboard();
		}
	};

#ifdef GRANITE_VULKAN_MT
	auto &workers = *Granite::Global::thread_group();
	// Workaround, cannot copy the lambda because of owning a unique_ptr.
	auto task = workers.create_task(move(work));
	task->flush();
#else
	work();
#endif
}

void Texture::update_checkerboard()
{
	LOGE("Failed to load texture: %s, falling back to a checkerboard.\n",
	     path.c_str());

	ImageInitialData initial = {};
	static const uint32_t checkerboard[] = {
			0xffffffffu, 0xffffffffu, 0xff000000u, 0xff000000u,
			0xffffffffu, 0xffffffffu, 0xff000000u, 0xff000000u,
			0xff000000u, 0xff000000u, 0xffffffffu, 0xffffffffu,
			0xff000000u, 0xff000000u, 0xffffffffu, 0xffffffffu,
	};
	initial.data = checkerboard;

	auto info = ImageCreateInfo::immutable_2d_image(4, 4, VK_FORMAT_R8G8B8A8_UNORM, false);
	info.misc = IMAGE_MISC_CONCURRENT_QUEUE_GRAPHICS_BIT | IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_GRAPHICS_BIT |
	            IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_COMPUTE_BIT;

	auto image = device->create_image(info, &initial);
	if (image)
		device->set_name(*image, path.c_str());
	replace_image(image);
}

void Texture::update_gtx(const Granite::SceneFormats::MemoryMappedTexture &mapped_file)
{
	if (mapped_file.empty())
	{
		update_checkerboard();
		return;
	}

	auto &layout = mapped_file.get_layout();

	ImageCreateInfo info = ImageCreateInfo::immutable_image(layout);
	info.swizzle = swizzle;
	info.flags = (mapped_file.get_flags() & Granite::SceneFormats::MEMORY_MAPPED_TEXTURE_CUBE_MAP_COMPATIBLE_BIT) ?
	             VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
	info.misc = IMAGE_MISC_CONCURRENT_QUEUE_GRAPHICS_BIT | IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_GRAPHICS_BIT |
	            IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_COMPUTE_BIT;

	mapped_file.remap_swizzle(info.swizzle);

	if (info.levels == 1 &&
	    (mapped_file.get_flags() & Granite::SceneFormats::MEMORY_MAPPED_TEXTURE_GENERATE_MIPMAP_ON_LOAD_BIT) != 0 &&
	    device->image_format_is_supported(info.format, VK_FORMAT_FEATURE_BLIT_SRC_BIT) &&
	    device->image_format_is_supported(info.format, VK_FORMAT_FEATURE_BLIT_DST_BIT))
	{
		info.levels = 0;
		info.misc |= IMAGE_MISC_GENERATE_MIPS_BIT;
	}

	if (!device->image_format_is_supported(info.format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
	{
		LOGE("Format (%u) is not supported!\n", unsigned(info.format));
		return;
	}

	auto staging = device->create_image_staging_buffer(layout);
	auto image = device->create_image_from_staging_buffer(info, &staging);
	if (image)
		device->set_name(*image, path.c_str());
	replace_image(image);
}

void Texture::update_gtx(unique_ptr<Granite::File> file, void *mapped)
{
	Granite::SceneFormats::MemoryMappedTexture mapped_file;
	if (!mapped_file.map_read(move(file), mapped))
	{
		LOGE("Failed to read texture.\n");
		return;
	}

	update_gtx(mapped_file);
}

void Texture::update_other(const void *data, size_t size)
{
	auto tex = Granite::load_texture_from_memory(data, size,
	                                    (format == VK_FORMAT_R8G8B8A8_SRGB ||
	                                     format == VK_FORMAT_UNDEFINED ||
	                                     format == VK_FORMAT_B8G8R8A8_SRGB ||
	                                     format == VK_FORMAT_A8B8G8R8_SRGB_PACK32) ?
	                                    Granite::ColorSpace::sRGB : Granite::ColorSpace::Linear);

	update_gtx(tex);
}

void Texture::load()
{
	if (!handle.get_nowait())
		init();
}

void Texture::unload()
{
	deinit();
	handle.reset();
}

void Texture::replace_image(ImageHandle handle_)
{
	auto old = this->handle.write_object(move(handle_));
	if (old)
		device->keep_handle_alive(move(old));

	if (enable_notification)
		device->get_texture_manager().notify_updated_texture(path, *this);
}

Image *Texture::get_image()
{
	auto ret = handle.get();
	VK_ASSERT(ret);
	return ret;
}

void Texture::set_enable_notification(bool enable)
{
	enable_notification = enable;
}

TextureManager::TextureManager(Device *device_)
	: device(device_)
{
}

Texture *TextureManager::request_texture(const std::string &path, VkFormat format, const VkComponentMapping &mapping)
{
	Util::Hasher hasher;
	hasher.string(path);
	auto deferred_hash = hasher.get();
	hasher.u32(format);
	hasher.u32(mapping.r);
	hasher.u32(mapping.g);
	hasher.u32(mapping.b);
	hasher.u32(mapping.a);
	auto hash = hasher.get();

	auto *ret = deferred_textures.find(deferred_hash);
	if (ret)
		return ret;

	ret = textures.find(hash);
	if (ret)
		return ret;

	ret = textures.emplace_yield(hash, device, path, format, mapping);
	if (!ret->init_texture())
		ret->update_checkerboard();
	return ret;
}

void TextureManager::register_texture_update_notification(const std::string &modified_path,
                                                          std::function<void(Texture &)> func)
{
	Util::Hasher hasher;
	hasher.string(modified_path);
	auto hash = hasher.get();
	auto *ret = deferred_textures.find(hash);
	if (ret)
		func(*ret);
	notifications[modified_path].push_back(move(func));
}

void TextureManager::notify_updated_texture(const std::string &path, Vulkan::Texture &texture)
{
	auto itr = notifications.find(path);
	if (itr != end(notifications))
		for (auto &f : itr->second)
			if (f)
				f(texture);
}

Texture *TextureManager::register_deferred_texture(const std::string &path)
{
	Util::Hasher hasher;
	hasher.string(path);
	auto hash = hasher.get();

	auto *ret = deferred_textures.find(hash);
	if (!ret)
	{
		auto *texture = deferred_textures.allocate(device);
		texture->set_path(path);
		texture->set_enable_notification(false);
		ret = deferred_textures.insert_yield(hash, texture);
	}
	return ret;
}

}
<commit_msg>Add fallback decode to texture manager.<commit_after>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * 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.
 */

#include "texture_manager.hpp"
#include "device.hpp"
#include "stb_image.h"
#include "memory_mapped_texture.hpp"
#include "texture_files.hpp"
#include "texture_decoder.hpp"

#ifdef GRANITE_VULKAN_MT
#include "thread_group.hpp"
#include "thread_id.hpp"
#endif

using namespace std;

namespace Vulkan
{
bool Texture::init_texture()
{
	if (!path.empty())
		return init();
	else
		return true;
}

Texture::Texture(Device *device_, const std::string &path_, VkFormat format_, const VkComponentMapping &swizzle_)
	: VolatileSource(path_), device(device_), format(format_), swizzle(swizzle_)
{
}

Texture::Texture(Device *device_)
	: device(device_), format(VK_FORMAT_UNDEFINED)
{
}

void Texture::set_path(const std::string &path_)
{
	path = path_;
}

void Texture::update(std::unique_ptr<Granite::File> file)
{
	auto *f = file.release();
	auto work = [f, this]() {
#if defined(GRANITE_VULKAN_MT) && defined(VULKAN_DEBUG)
		LOGI("Loading texture in thread index: %u\n", get_current_thread_index());
#endif
		unique_ptr<Granite::File> updated_file{f};
		auto size = updated_file->get_size();
		void *mapped = updated_file->map();
		if (size && mapped)
		{
			if (Granite::SceneFormats::MemoryMappedTexture::is_header(mapped, size))
				update_gtx(move(updated_file), mapped);
			else
				update_other(mapped, size);
			device->get_texture_manager().notify_updated_texture(path, *this);
		}
		else
		{
			LOGE("Failed to map texture file ...\n");
			update_checkerboard();
		}
	};

#ifdef GRANITE_VULKAN_MT
	auto &workers = *Granite::Global::thread_group();
	// Workaround, cannot copy the lambda because of owning a unique_ptr.
	auto task = workers.create_task(move(work));
	task->flush();
#else
	work();
#endif
}

void Texture::update_checkerboard()
{
	LOGE("Failed to load texture: %s, falling back to a checkerboard.\n",
	     path.c_str());

	ImageInitialData initial = {};
	static const uint32_t checkerboard[] = {
			0xffffffffu, 0xffffffffu, 0xff000000u, 0xff000000u,
			0xffffffffu, 0xffffffffu, 0xff000000u, 0xff000000u,
			0xff000000u, 0xff000000u, 0xffffffffu, 0xffffffffu,
			0xff000000u, 0xff000000u, 0xffffffffu, 0xffffffffu,
	};
	initial.data = checkerboard;

	auto info = ImageCreateInfo::immutable_2d_image(4, 4, VK_FORMAT_R8G8B8A8_UNORM, false);
	info.misc = IMAGE_MISC_CONCURRENT_QUEUE_GRAPHICS_BIT | IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_GRAPHICS_BIT |
	            IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_COMPUTE_BIT;

	auto image = device->create_image(info, &initial);
	if (image)
		device->set_name(*image, path.c_str());
	replace_image(image);
}

void Texture::update_gtx(const Granite::SceneFormats::MemoryMappedTexture &mapped_file)
{
	if (mapped_file.empty())
	{
		update_checkerboard();
		return;
	}

	auto &layout = mapped_file.get_layout();

	Vulkan::ImageHandle image;
	if (!device->image_format_is_supported(layout.get_format(), VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
	    format_compression_type(layout.get_format()) != FormatCompressionType::Uncompressed)
	{
		LOGI("Compressed format #%u is not supported, falling back to compute decode of compressed image.\n",
		     unsigned(layout.get_format()));
		auto cmd = device->request_command_buffer(CommandBuffer::Type::AsyncCompute);
		image = Granite::decode_compressed_image(*cmd, layout, swizzle);
		Semaphore sem;
		device->submit(cmd, nullptr, 1, &sem);
		device->add_wait_semaphore(CommandBuffer::Type::Generic, sem, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, true);
	}
	else
	{
		ImageCreateInfo info = ImageCreateInfo::immutable_image(layout);
		info.swizzle = swizzle;
		info.flags = (mapped_file.get_flags() & Granite::SceneFormats::MEMORY_MAPPED_TEXTURE_CUBE_MAP_COMPATIBLE_BIT) ?
                         VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT :
                         0;
		info.misc = IMAGE_MISC_CONCURRENT_QUEUE_GRAPHICS_BIT | IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_GRAPHICS_BIT |
		            IMAGE_MISC_CONCURRENT_QUEUE_ASYNC_COMPUTE_BIT;

		mapped_file.remap_swizzle(info.swizzle);

		if (info.levels == 1 &&
		    (mapped_file.get_flags() & Granite::SceneFormats::MEMORY_MAPPED_TEXTURE_GENERATE_MIPMAP_ON_LOAD_BIT) != 0 &&
		    device->image_format_is_supported(info.format, VK_FORMAT_FEATURE_BLIT_SRC_BIT) &&
		    device->image_format_is_supported(info.format, VK_FORMAT_FEATURE_BLIT_DST_BIT))
		{
			info.levels = 0;
			info.misc |= IMAGE_MISC_GENERATE_MIPS_BIT;
		}

		if (!device->image_format_is_supported(info.format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
		{
			LOGE("Format (%u) is not supported!\n", unsigned(info.format));
			return;
		}

		auto staging = device->create_image_staging_buffer(layout);
		image = device->create_image_from_staging_buffer(info, &staging);
	}

	if (image)
		device->set_name(*image, path.c_str());
	replace_image(image);
}

void Texture::update_gtx(unique_ptr<Granite::File> file, void *mapped)
{
	Granite::SceneFormats::MemoryMappedTexture mapped_file;
	if (!mapped_file.map_read(move(file), mapped))
	{
		LOGE("Failed to read texture.\n");
		return;
	}

	update_gtx(mapped_file);
}

void Texture::update_other(const void *data, size_t size)
{
	auto tex = Granite::load_texture_from_memory(data, size,
	                                    (format == VK_FORMAT_R8G8B8A8_SRGB ||
	                                     format == VK_FORMAT_UNDEFINED ||
	                                     format == VK_FORMAT_B8G8R8A8_SRGB ||
	                                     format == VK_FORMAT_A8B8G8R8_SRGB_PACK32) ?
	                                    Granite::ColorSpace::sRGB : Granite::ColorSpace::Linear);

	update_gtx(tex);
}

void Texture::load()
{
	if (!handle.get_nowait())
		init();
}

void Texture::unload()
{
	deinit();
	handle.reset();
}

void Texture::replace_image(ImageHandle handle_)
{
	auto old = this->handle.write_object(move(handle_));
	if (old)
		device->keep_handle_alive(move(old));

	if (enable_notification)
		device->get_texture_manager().notify_updated_texture(path, *this);
}

Image *Texture::get_image()
{
	auto ret = handle.get();
	VK_ASSERT(ret);
	return ret;
}

void Texture::set_enable_notification(bool enable)
{
	enable_notification = enable;
}

TextureManager::TextureManager(Device *device_)
	: device(device_)
{
}

Texture *TextureManager::request_texture(const std::string &path, VkFormat format, const VkComponentMapping &mapping)
{
	Util::Hasher hasher;
	hasher.string(path);
	auto deferred_hash = hasher.get();
	hasher.u32(format);
	hasher.u32(mapping.r);
	hasher.u32(mapping.g);
	hasher.u32(mapping.b);
	hasher.u32(mapping.a);
	auto hash = hasher.get();

	auto *ret = deferred_textures.find(deferred_hash);
	if (ret)
		return ret;

	ret = textures.find(hash);
	if (ret)
		return ret;

	ret = textures.emplace_yield(hash, device, path, format, mapping);
	if (!ret->init_texture())
		ret->update_checkerboard();
	return ret;
}

void TextureManager::register_texture_update_notification(const std::string &modified_path,
                                                          std::function<void(Texture &)> func)
{
	Util::Hasher hasher;
	hasher.string(modified_path);
	auto hash = hasher.get();
	auto *ret = deferred_textures.find(hash);
	if (ret)
		func(*ret);
	notifications[modified_path].push_back(move(func));
}

void TextureManager::notify_updated_texture(const std::string &path, Vulkan::Texture &texture)
{
	auto itr = notifications.find(path);
	if (itr != end(notifications))
		for (auto &f : itr->second)
			if (f)
				f(texture);
}

Texture *TextureManager::register_deferred_texture(const std::string &path)
{
	Util::Hasher hasher;
	hasher.string(path);
	auto hash = hasher.get();

	auto *ret = deferred_textures.find(hash);
	if (!ret)
	{
		auto *texture = deferred_textures.allocate(device);
		texture->set_path(path);
		texture->set_enable_notification(false);
		ret = deferred_textures.insert_yield(hash, texture);
	}
	return ret;
}

}
<|endoftext|>


<commit_before>
#include <iostream>
#include <thread>
#include <deque>
#include <exception>
#include <mutex>

// #include <condition_variable>
// #include <mutex>

void busywait(int lmax) {
    for(int i=0; i<lmax; i++) {
        for(int j=0; j<lmax; j++) {
            for(int k=0; k<lmax; k++) {
            }
        }
    }
}

bool WAITFOREXIT = true;
bool NOWAITFOREXIT = false;

class StopIteration: public std::exception {
    virtual const char* what() const throw() {
        return "StopIteration";
    }
};

template <class T>
class Queue {
private:
    std::deque<T> m_queue;
    std::mutex m_mutex;
public:
    void put(T item) {
        m_queue.push_back(item);
        std::cout << "APPEND " << item << std::endl;
    }
    T get() {  //        std::cout << "Really ought to check the queue length first" << std::endl;
        T result;
        m_mutex.lock();
        if (m_queue.empty()) {
            m_mutex.unlock();
            throw StopIteration();
        }
        result = m_queue.front();
        m_queue.pop_front();
        m_mutex.unlock();
        return result;
    }
};

class Actor { // I know this is bad practice. This is a sketch remember?
public:
    std::thread m_Thread;
    bool m_let_me_finish;

protected:
    virtual void main() {
        for(int i=0; i<20; i++) {
            busywait(350);
            std::cout << "              Actor::main " << std::this_thread::get_id() << " Executing:" << i << std::endl;
        }
    }

public:
    Actor(): m_Thread(), m_let_me_finish(false) { };
    Actor(bool X): m_Thread(), m_let_me_finish(X) { };
    void run() {
        m_Thread = std::thread(&Actor::main, this);
        if (!m_let_me_finish) {
            std::cout << "m_let_me_finish:" << m_let_me_finish << std::endl;
            m_Thread.detach();
        }
    }
    ~Actor() {
        if (m_let_me_finish) {
            m_Thread.join(); // Probably want to do something different?
        }
    }
};

class Dramatic : public Actor {     // Example Actor
public:
    Dramatic(): Actor() { };        // Always initialise cleanly...
    Dramatic(bool X): Actor(X) { }; // Always initialise cleanly...
    void main() {
        for(int i=0; i<20; i++) {
            busywait(95);
            std::cout << "             I am DRAMATIC " << std::this_thread::get_id() << " Executing:" << i << std::endl;
        }
    }
};

void actortest() {
    Actor simple1;
    Actor simple2(NOWAITFOREXIT);
//    Dramatic Sherlock(WAITFOREXIT);
//    Dramatic Sherlock(NOWAITFOREXIT);
    Dramatic Sherlock;

    simple1.run();
    simple2.run();
    Sherlock.run();

    for(int i=0; i<10; i++) {
        busywait(100);
        std::cout << "                                          Display From MainThread "<< std::this_thread::get_id() <<" ?:" << i << std::endl;
    }
}

int main(int argc, char *argv[]) {
    Queue<int> q;

    std::cout << "Hello" << std::endl;
    std::cout << "World" << std::endl;

    for(int i=0; i<10; i++) {
        q.put(i);
    }
    while(true) {
        try {
            std::cout << "POP: " << q.get() << std::endl;
        } catch (StopIteration& e) {
            break;
        }
    }

    // actortest();
    std::cout<<"Exit of Main function"<<std::endl;

    return 0;
}
<commit_msg>Improve queue for threadsafety, usage styles, create producer/consumer example<commit_after>
#include <iostream>
#include <thread>
#include <deque>
#include <exception>
#include <mutex>
#include <chrono>

// #include <condition_variable>

bool WAITFOREXIT = true;
bool NOWAITFOREXIT = false;

void busywait(int lmax) {
    for(int i=0; i<lmax; i++) {
        for(int j=0; j<lmax; j++) {
            for(int k=0; k<lmax; k++) {
            }
        }
    }
}

class EmptyQueue: public std::exception {
    virtual const char* what() const throw() {
        return "EmptyQueue";
    }
};

class EmptyQueueTimeout: public std::exception {
    virtual const char* what() const throw() {
        return "EmptyQueueTimeout";
    }
};

using namespace std::chrono_literals;

template <class T>
class Queue {
    std::deque<T> m_queue;
    std::mutex m_mutex;
public:

    void put(T item) {
        m_mutex.lock();
        m_queue.push_back(item);
        m_mutex.unlock();
    }

    T get_nowait() {
        T result;
        m_mutex.lock();
        if (m_queue.empty()) {
            m_mutex.unlock();
            throw EmptyQueue();
        }
        result = m_queue.front();
        m_queue.pop_front();
        m_mutex.unlock();
        return result;
    }

    T get() {
        return get_timeout(0);
    }

    T get_timeout(int timeout_ms) {
        int so_far_ms = 0;
        T result;
        while (true) {
            m_mutex.lock();
            if (!m_queue.empty()) {
                break;
            }
            m_mutex.unlock();
            std::this_thread::sleep_for(2ms);
            so_far_ms += 2;
            if (timeout_ms and so_far_ms > timeout_ms) {
                throw EmptyQueueTimeout();
            }
        }

        result = m_queue.front();
        m_queue.pop_front();
        m_mutex.unlock();
        return result;
    }
};

class Actor { // I know this is bad practice. This is a sketch remember?
public:
    std::thread m_Thread;
    bool m_let_me_finish;

protected:
    virtual void main() {
        for(int i=0; i<20; i++) {
            busywait(350);
            std::cout << "              Actor::main " << std::this_thread::get_id() << " Executing:" << i << std::endl;
        }
    }

public:
    Actor(): m_Thread(), m_let_me_finish(false) { };
    Actor(bool X): m_Thread(), m_let_me_finish(X) { };
    void run() {
        m_Thread = std::thread(&Actor::main, this);
        if (!m_let_me_finish) {
            m_Thread.detach();
        }
    }
    ~Actor() {
        if (m_let_me_finish) {
            m_Thread.join(); // Appropriate?
        }
    }
};

class Producer : public Actor {
public:
    std::string m_tag;
    Queue<int> * q;

    Producer(std::string name): Actor(), m_tag(name) {}
    Producer(std::string name, Queue<int> * Q): Actor(), m_tag(name), q(Q) {}
    void set_outbox(Queue<int> * Q) {
        q = Q;
    }
    void main() {
        for(int i=0; i<20; i++) {
            busywait(95);
            q->put(i);
        }
        q->put(-1);
    }
};

class Consumer : public Actor {
public:
    std::string m_tag;
    Queue<int> * q;

    Consumer(std::string name): Actor(), m_tag(name) {}
    Consumer(std::string name, Queue<int> * Q): Actor(), m_tag(name), q(Q) {}
    void set_inbox(Queue<int> * Q) {
        q = Q;
    }
    void main() {
        while(true) {
            int result;
            busywait(105);
            try {
                result = q->get_timeout(10);
            } catch (EmptyQueueTimeout& e) {
                break;
            }
            std::cout << "CONSUMER " << m_tag << " " << result << std::endl;
        }
        std::cout << "CONSUMER " << m_tag << " exitting" << std::endl;
    }
};

int main(int argc, char *argv[]) {
    Queue<int> q;

    Producer P1("P1", &q);
    Producer P2("P2");
    Consumer C1("C1", &q);
    P2.set_outbox(&q);

    P1.run();
    P2.run();
    C1.run();

    for(int i=0; i<10; i++) {
            busywait(200);
    }

    std::cout<<"Exit of Main function"<<std::endl;

    return 0;
}
<|endoftext|>


<commit_before>#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_server/Handler.hxx"
#include "http_headers.hxx"
#include "direct.hxx"
#include "RootPool.hxx"
#include "pool.hxx"
#include "istream/istream.hxx"
#include "istream/istream_catch.hxx"
#include "fb_pool.hxx"
#include "system/fd_util.h"
#include "event/Event.hxx"

#include <stdio.h>
#include <stdlib.h>

struct Instance final : HttpServerConnectionHandler {
    /* virtual methods from class HttpServerConnectionHandler */
    void HandleHttpRequest(struct http_server_request &request,
                           struct async_operation_ref &async_ref) override;

    void LogHttpRequest(struct http_server_request &,
                        http_status_t, off_t,
                        uint64_t, uint64_t) override {}

    void HttpConnectionError(GError *error) override;
    void HttpConnectionClosed() override;
};

static GError *
catch_callback(GError *error, gcc_unused void *ctx)
{
    fprintf(stderr, "%s\n", error->message);
    g_error_free(error);
    return nullptr;
}

void
Instance::HandleHttpRequest(struct http_server_request &request,
                            gcc_unused struct async_operation_ref &async_ref)
{
    http_server_response(&request, HTTP_STATUS_OK, HttpHeaders(),
                         istream_catch_new(request.pool, *request.body,
                                           catch_callback, nullptr));
    http_server_connection_close(request.connection);
}

void
Instance::HttpConnectionError(GError *error)
{
    g_printerr("%s\n", error->message);
    g_error_free(error);
}

void
Instance::HttpConnectionClosed()
{
}

static void
test_catch(EventLoop &event_loop, struct pool *pool)
{
    pool = pool_new_libc(pool, "catch");

    int fds[2];
    if (socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
        perror("socketpair()");
        abort();
    }

    static constexpr char request[] =
        "POST / HTTP/1.1\r\nContent-Length: 1024\r\n\r\nfoo";
    send(fds[1], request, sizeof(request) - 1, 0);

    Instance instance;
    HttpServerConnection *connection;
    http_server_connection_new(pool, fds[0], FdType::FD_SOCKET,
                               nullptr, nullptr,
                               nullptr, nullptr,
                               true, instance,
                               &connection);
    pool_unref(pool);

    event_loop.Dispatch();

    close(fds[1]);
}

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

    direct_global_init();
    EventLoop event_loop;
    fb_pool_init(false);

    test_catch(event_loop, RootPool());

    fb_pool_deinit();
}
<commit_msg>test/t_http_server: move pool to struct Instance<commit_after>#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_server/Handler.hxx"
#include "http_headers.hxx"
#include "direct.hxx"
#include "RootPool.hxx"
#include "pool.hxx"
#include "istream/istream.hxx"
#include "istream/istream_catch.hxx"
#include "fb_pool.hxx"
#include "system/fd_util.h"
#include "event/Event.hxx"

#include <stdio.h>
#include <stdlib.h>

struct Instance final : HttpServerConnectionHandler {
    struct pool *pool;

    explicit Instance(struct pool &_pool)
        :pool(pool_new_libc(&_pool, "catch")) {}

    /* virtual methods from class HttpServerConnectionHandler */
    void HandleHttpRequest(struct http_server_request &request,
                           struct async_operation_ref &async_ref) override;

    void LogHttpRequest(struct http_server_request &,
                        http_status_t, off_t,
                        uint64_t, uint64_t) override {}

    void HttpConnectionError(GError *error) override;
    void HttpConnectionClosed() override;
};

static GError *
catch_callback(GError *error, gcc_unused void *ctx)
{
    fprintf(stderr, "%s\n", error->message);
    g_error_free(error);
    return nullptr;
}

void
Instance::HandleHttpRequest(struct http_server_request &request,
                            gcc_unused struct async_operation_ref &async_ref)
{
    http_server_response(&request, HTTP_STATUS_OK, HttpHeaders(),
                         istream_catch_new(request.pool, *request.body,
                                           catch_callback, nullptr));
    http_server_connection_close(request.connection);
}

void
Instance::HttpConnectionError(GError *error)
{
    g_printerr("%s\n", error->message);
    g_error_free(error);
}

void
Instance::HttpConnectionClosed()
{
}

static void
test_catch(EventLoop &event_loop, struct pool *_pool)
{
    int fds[2];
    if (socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
        perror("socketpair()");
        abort();
    }

    static constexpr char request[] =
        "POST / HTTP/1.1\r\nContent-Length: 1024\r\n\r\nfoo";
    send(fds[1], request, sizeof(request) - 1, 0);

    Instance instance(*_pool);
    HttpServerConnection *connection;
    http_server_connection_new(instance.pool, fds[0], FdType::FD_SOCKET,
                               nullptr, nullptr,
                               nullptr, nullptr,
                               true, instance,
                               &connection);
    pool_unref(instance.pool);

    event_loop.Dispatch();

    close(fds[1]);
}

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

    direct_global_init();
    EventLoop event_loop;
    fb_pool_init(false);

    test_catch(event_loop, RootPool());

    fb_pool_deinit();
}
<|endoftext|>


<commit_before>// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/data/smart_buffer.h>

using namespace vespalib;

void checkMemory(const vespalib::string &expect, const Memory &mem) {
    EXPECT_EQUAL(expect, vespalib::string(mem.data, mem.size));
}

void checkBuffer(const vespalib::string &expect, SmartBuffer &buf) {
    TEST_DO(checkMemory(expect, buf.obtain()));
}

void write_buf(const vespalib::string &str, SmartBuffer &buf) {
    WritableMemory mem = buf.reserve(str.size());
    for (size_t i = 0; i < str.size(); ++i) {
        mem.data[i] = str.data()[i];
    }
    buf.commit(str.size());
}

TEST("require that basic read/write works") {
    SmartBuffer buf(3);
    TEST_DO(checkBuffer("", buf));
    { // read from empty buffer
        EXPECT_EQUAL(0u, buf.obtain().size);
    }
    { // write to buffer
        WritableMemory mem = buf.reserve(10);
        TEST_DO(checkBuffer("", buf));
        EXPECT_LESS_EQUAL(10u, mem.size);
        mem.data[0] = 'a';
        mem.data[1] = 'b';
        mem.data[2] = 'c';
        EXPECT_EQUAL(&buf, &buf.commit(3));
        mem = buf.reserve(0);
        TEST_DO(checkBuffer("abc", buf));
        EXPECT_LESS_EQUAL(0u, mem.size);
    }
    { // read without evicting last byte
        Memory mem = buf.obtain();
        TEST_DO(checkBuffer("abc", buf));
        TEST_DO(checkMemory("abc", mem));
        EXPECT_EQUAL(&buf, &buf.evict(2));
        mem = buf.obtain();
        TEST_DO(checkBuffer("c", buf));
        TEST_DO(checkMemory("c", mem));
        mem = buf.obtain();
        TEST_DO(checkBuffer("c", buf));
        TEST_DO(checkMemory("c", mem));
    }
    { // write more to buffer
        WritableMemory mem = buf.reserve(10);
        EXPECT_LESS_EQUAL(10u, mem.size);
        TEST_DO(checkBuffer("c", buf));
        mem.data[0] = 'd';
        EXPECT_EQUAL(&buf, &buf.commit(1));
        mem = buf.reserve(5);
        TEST_DO(checkBuffer("cd", buf));
        EXPECT_LESS_EQUAL(5u, mem.size);
    }
    { // read until end
        Memory mem = buf.obtain();
        TEST_DO(checkBuffer("cd", buf));
        TEST_DO(checkMemory("cd", mem));
        EXPECT_EQUAL(&buf, &buf.evict(1));
        mem = buf.obtain();
        TEST_DO(checkBuffer("d", buf));
        TEST_DO(checkMemory("d", mem));
        EXPECT_EQUAL(&buf, &buf.evict(1));
        mem = buf.obtain();
        TEST_DO(checkBuffer("", buf));
        TEST_DO(checkMemory("", mem));
    }
}

TEST("require that requested initial size is not adjusted") {
    SmartBuffer buf(400);
    EXPECT_EQUAL(buf.capacity(), 400u);
}

TEST("require that buffer auto-resets when empty") {
    SmartBuffer buf(64);
    EXPECT_EQUAL(buf.reserve(10).size, 64u);
    write_buf("abc", buf);
    EXPECT_EQUAL(buf.reserve(10).size, 61u);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(10).size, 64u);
}

TEST("require that buffer can grow") {
    SmartBuffer buf(64);
    EXPECT_EQUAL(buf.capacity(), 64u);
    write_buf("abc", buf);
    write_buf("abc", buf);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(70).size, size_t(128 - 3));
    TEST_DO(checkBuffer("abc", buf));
    EXPECT_EQUAL(buf.capacity(), 128u);
}

TEST("require that buffer can grow more than 2x") {
    SmartBuffer buf(64);
    EXPECT_EQUAL(buf.capacity(), 64u);
    write_buf("abc", buf);
    write_buf("abc", buf);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(170).size, 170u);
    TEST_DO(checkBuffer("abc", buf));
    EXPECT_EQUAL(buf.capacity(), 173u);
}

TEST("require that buffer can be compacted") {
    SmartBuffer buf(16);
    EXPECT_EQUAL(buf.capacity(), 16u);
    write_buf("abc", buf);
    write_buf("abc", buf);
    buf.evict(3);
    write_buf("abc", buf);
    buf.evict(3);
    write_buf("abc", buf);
    buf.evict(3);
    write_buf("abc", buf);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(0).size, 1u);
    write_buf("abc", buf);
    TEST_DO(checkBuffer("abcabc", buf));
    EXPECT_EQUAL(buf.capacity(), 16u);
    EXPECT_EQUAL(buf.reserve(0).size, 10u);
}

TEST_MAIN() { TEST_RUN_ALL(); }
<commit_msg>test empty smart buffer<commit_after>// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/data/smart_buffer.h>

using namespace vespalib;

void checkMemory(const vespalib::string &expect, const Memory &mem) {
    EXPECT_EQUAL(expect, vespalib::string(mem.data, mem.size));
}

void checkBuffer(const vespalib::string &expect, SmartBuffer &buf) {
    TEST_DO(checkMemory(expect, buf.obtain()));
}

void write_buf(const vespalib::string &str, SmartBuffer &buf) {
    WritableMemory mem = buf.reserve(str.size());
    for (size_t i = 0; i < str.size(); ++i) {
        mem.data[i] = str.data()[i];
    }
    buf.commit(str.size());
}

TEST("require that basic read/write works") {
    SmartBuffer buf(3);
    TEST_DO(checkBuffer("", buf));
    { // read from empty buffer
        EXPECT_EQUAL(0u, buf.obtain().size);
    }
    { // write to buffer
        WritableMemory mem = buf.reserve(10);
        TEST_DO(checkBuffer("", buf));
        EXPECT_LESS_EQUAL(10u, mem.size);
        mem.data[0] = 'a';
        mem.data[1] = 'b';
        mem.data[2] = 'c';
        EXPECT_EQUAL(&buf, &buf.commit(3));
        mem = buf.reserve(0);
        TEST_DO(checkBuffer("abc", buf));
        EXPECT_LESS_EQUAL(0u, mem.size);
    }
    { // read without evicting last byte
        Memory mem = buf.obtain();
        TEST_DO(checkBuffer("abc", buf));
        TEST_DO(checkMemory("abc", mem));
        EXPECT_EQUAL(&buf, &buf.evict(2));
        mem = buf.obtain();
        TEST_DO(checkBuffer("c", buf));
        TEST_DO(checkMemory("c", mem));
        mem = buf.obtain();
        TEST_DO(checkBuffer("c", buf));
        TEST_DO(checkMemory("c", mem));
    }
    { // write more to buffer
        WritableMemory mem = buf.reserve(10);
        EXPECT_LESS_EQUAL(10u, mem.size);
        TEST_DO(checkBuffer("c", buf));
        mem.data[0] = 'd';
        EXPECT_EQUAL(&buf, &buf.commit(1));
        mem = buf.reserve(5);
        TEST_DO(checkBuffer("cd", buf));
        EXPECT_LESS_EQUAL(5u, mem.size);
    }
    { // read until end
        Memory mem = buf.obtain();
        TEST_DO(checkBuffer("cd", buf));
        TEST_DO(checkMemory("cd", mem));
        EXPECT_EQUAL(&buf, &buf.evict(1));
        mem = buf.obtain();
        TEST_DO(checkBuffer("d", buf));
        TEST_DO(checkMemory("d", mem));
        EXPECT_EQUAL(&buf, &buf.evict(1));
        mem = buf.obtain();
        TEST_DO(checkBuffer("", buf));
        TEST_DO(checkMemory("", mem));
    }
}

TEST("require that requested initial size is not adjusted") {
    SmartBuffer buf(400);
    EXPECT_EQUAL(buf.capacity(), 400u);
}

TEST("require that buffer auto-resets when empty") {
    SmartBuffer buf(64);
    EXPECT_EQUAL(buf.reserve(10).size, 64u);
    write_buf("abc", buf);
    EXPECT_EQUAL(buf.reserve(10).size, 61u);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(10).size, 64u);
}

TEST("require that buffer can grow") {
    SmartBuffer buf(64);
    EXPECT_EQUAL(buf.capacity(), 64u);
    write_buf("abc", buf);
    write_buf("abc", buf);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(70).size, size_t(128 - 3));
    TEST_DO(checkBuffer("abc", buf));
    EXPECT_EQUAL(buf.capacity(), 128u);
}

TEST("require that buffer can grow more than 2x") {
    SmartBuffer buf(64);
    EXPECT_EQUAL(buf.capacity(), 64u);
    write_buf("abc", buf);
    write_buf("abc", buf);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(170).size, 170u);
    TEST_DO(checkBuffer("abc", buf));
    EXPECT_EQUAL(buf.capacity(), 173u);
}

TEST("require that buffer can be compacted") {
    SmartBuffer buf(16);
    EXPECT_EQUAL(buf.capacity(), 16u);
    write_buf("abc", buf);
    write_buf("abc", buf);
    buf.evict(3);
    write_buf("abc", buf);
    buf.evict(3);
    write_buf("abc", buf);
    buf.evict(3);
    write_buf("abc", buf);
    buf.evict(3);
    EXPECT_EQUAL(buf.reserve(0).size, 1u);
    write_buf("abc", buf);
    TEST_DO(checkBuffer("abcabc", buf));
    EXPECT_EQUAL(buf.capacity(), 16u);
    EXPECT_EQUAL(buf.reserve(0).size, 10u);
}

TEST("require that a completely empty buffer can be created") {
    SmartBuffer buf(0);
    EXPECT_EQUAL(buf.capacity(), 0u);
    EXPECT_TRUE(buf.obtain().data == nullptr);
}

TEST_MAIN() { TEST_RUN_ALL(); }
<|endoftext|>


<commit_before>//
// Copyright (c) 2008-2016 the Urho3D project.
//
// 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.
//

#include "../Precompiled.h"

#include "../Core/Context.h"
#include "../Scene/Component.h"
#include "../Scene/ReplicationState.h"
#include "../Scene/Scene.h"
#include "../Scene/SceneEvents.h"
#ifdef URHO3D_PHYSICS
#include "../Physics/PhysicsWorld.h"
#endif
#ifdef URHO3D_URHO2D
#include "../Urho2D/PhysicsWorld2D.h"
#endif

#include "../DebugNew.h"
#include "../Resource/JSONValue.h"

#ifdef _MSC_VER
#pragma warning(disable:6293)
#endif

namespace Urho3D
{

Component::Component(Context* context) :
    Animatable(context),
    node_(0),
    id_(0),
    networkUpdate_(false),
    enabled_(true)
{
}

Component::~Component()
{
}

bool Component::Save(Serializer& dest) const
{
    // Write type and ID
    if (!dest.WriteStringHash(GetType()))
        return false;
    if (!dest.WriteUInt(id_))
        return false;

    // Write attributes
    return Animatable::Save(dest);
}

bool Component::SaveXML(XMLElement& dest) const
{
    // Write type and ID
    if (!dest.SetString("type", GetTypeName()))
        return false;
    if (!dest.SetUInt("id", id_))
        return false;

    // Write attributes
    return Animatable::SaveXML(dest);
}

bool Component::SaveJSON(JSONValue& dest) const
{
    // Write type and ID
    dest.Set("type", GetTypeName());
    dest.Set("id", id_);

    // Write attributes
    return Animatable::SaveJSON(dest);
}

void Component::MarkNetworkUpdate()
{
    if (!networkUpdate_ && id_ < FIRST_LOCAL_ID)
    {
        Scene* scene = GetScene();
        if (scene)
        {
            scene->MarkNetworkUpdate(this);
            networkUpdate_ = true;
        }
    }
}

void Component::GetDependencyNodes(PODVector<Node*>& dest)
{
}

void Component::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
{
}

void Component::SetEnabled(bool enable)
{
    if (enable != enabled_)
    {
        enabled_ = enable;
        OnSetEnabled();
        MarkNetworkUpdate();

        // Send change event for the component
        Scene* scene = GetScene();
        if (scene)
        {
            using namespace ComponentEnabledChanged;

            VariantMap& eventData = GetEventDataMap();
            eventData[P_SCENE] = scene;
            eventData[P_NODE] = node_;
            eventData[P_COMPONENT] = this;

            scene->SendEvent(E_COMPONENTENABLEDCHANGED, eventData);
        }
    }
}

void Component::Remove()
{
    if (node_)
        node_->RemoveComponent(this);
}

Scene* Component::GetScene() const
{
    return node_ ? node_->GetScene() : 0;
}

void Component::AddReplicationState(ComponentReplicationState* state)
{
    if (!networkState_)
        AllocateNetworkState();

    networkState_->replicationStates_.Push(state);
}

void Component::PrepareNetworkUpdate()
{
    if (!networkState_)
        AllocateNetworkState();

    const Vector<AttributeInfo>* attributes = networkState_->attributes_;
    if (!attributes)
        return;

    unsigned numAttributes = attributes->Size();

    if (networkState_->currentValues_.Size() != numAttributes)
    {
        networkState_->currentValues_.Resize(numAttributes);
        networkState_->previousValues_.Resize(numAttributes);

        // Copy the default attribute values to the previous state as a starting point
        for (unsigned i = 0; i < numAttributes; ++i)
            networkState_->previousValues_[i] = attributes->At(i).defaultValue_;
    }

    // Check for attribute changes
    for (unsigned i = 0; i < numAttributes; ++i)
    {
        const AttributeInfo& attr = attributes->At(i);

        if (animationEnabled_ && IsAnimatedNetworkAttribute(attr))
            continue;

        OnGetAttribute(attr, networkState_->currentValues_[i]);

        if (networkState_->currentValues_[i] != networkState_->previousValues_[i])
        {
            networkState_->previousValues_[i] = networkState_->currentValues_[i];

            // Mark the attribute dirty in all replication states that are tracking this component
            for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin();
                 j != networkState_->replicationStates_.End(); ++j)
            {
                ComponentReplicationState* compState = static_cast<ComponentReplicationState*>(*j);
                compState->dirtyAttributes_.Set(i);

                // Add component's parent node to the dirty set if not added yet
                NodeReplicationState* nodeState = compState->nodeState_;
                if (!nodeState->markedDirty_)
                {
                    nodeState->markedDirty_ = true;
                    nodeState->sceneState_->dirtyNodes_.Insert(node_->GetID());
                }
            }
        }
    }

    networkUpdate_ = false;
}

void Component::CleanupConnection(Connection* connection)
{
    if (networkState_)
    {
        for (unsigned i = networkState_->replicationStates_.Size() - 1; i < networkState_->replicationStates_.Size(); --i)
        {
            if (networkState_->replicationStates_[i]->connection_ == connection)
                networkState_->replicationStates_.Erase(i);
        }
    }
}

void Component::OnAttributeAnimationAdded()
{
    if (attributeAnimationInfos_.Size() == 1)
        SubscribeToEvent(GetScene(), E_ATTRIBUTEANIMATIONUPDATE, URHO3D_HANDLER(Component, HandleAttributeAnimationUpdate));
}

void Component::OnAttributeAnimationRemoved()
{
    if (attributeAnimationInfos_.Empty())
        UnsubscribeFromEvent(GetScene(), E_ATTRIBUTEANIMATIONUPDATE);
}

void Component::OnNodeSet(Node* node)
{
}

void Component::OnSceneSet(Scene* scene)
{
}

void Component::OnMarkedDirty(Node* node)
{
}

void Component::OnNodeSetEnabled(Node* node)
{
}

void Component::SetID(unsigned id)
{
    id_ = id;
}

void Component::SetNode(Node* node)
{
    node_ = node;
    OnNodeSet(node_);
}

Component* Component::GetComponent(StringHash type) const
{
    return node_ ? node_->GetComponent(type) : 0;
}

bool Component::IsEnabledEffective() const
{
    return enabled_ && node_ && node_->IsEnabled();
}

void Component::GetComponents(PODVector<Component*>& dest, StringHash type) const
{
    if (node_)
        node_->GetComponents(dest, type);
    else
        dest.Clear();
}

void Component::HandleAttributeAnimationUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace AttributeAnimationUpdate;

    UpdateAttributeAnimations(eventData[P_TIMESTEP].GetFloat());
}

Component* Component::GetFixedUpdateSource()
{
    Component* ret = 0;
    Scene* scene = GetScene();

    if (scene)
    {
#ifdef URHO3D_PHYSICS
        ret = scene->GetComponent<PhysicsWorld>();
#endif
#ifdef URHO3D_URHO2D
        if (!ret)
            ret = scene->GetComponent<PhysicsWorld2D>();
#endif
    }

    return ret;
}

}
<commit_msg>Include DebugNew.h last in Component.cpp to match convention used elsewhere.<commit_after>//
// Copyright (c) 2008-2016 the Urho3D project.
//
// 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.
//

#include "../Precompiled.h"

#include "../Core/Context.h"
#include "../Resource/JSONValue.h"
#include "../Scene/Component.h"
#include "../Scene/ReplicationState.h"
#include "../Scene/Scene.h"
#include "../Scene/SceneEvents.h"
#ifdef URHO3D_PHYSICS
#include "../Physics/PhysicsWorld.h"
#endif
#ifdef URHO3D_URHO2D
#include "../Urho2D/PhysicsWorld2D.h"
#endif

#include "../DebugNew.h"

#ifdef _MSC_VER
#pragma warning(disable:6293)
#endif

namespace Urho3D
{

Component::Component(Context* context) :
    Animatable(context),
    node_(0),
    id_(0),
    networkUpdate_(false),
    enabled_(true)
{
}

Component::~Component()
{
}

bool Component::Save(Serializer& dest) const
{
    // Write type and ID
    if (!dest.WriteStringHash(GetType()))
        return false;
    if (!dest.WriteUInt(id_))
        return false;

    // Write attributes
    return Animatable::Save(dest);
}

bool Component::SaveXML(XMLElement& dest) const
{
    // Write type and ID
    if (!dest.SetString("type", GetTypeName()))
        return false;
    if (!dest.SetUInt("id", id_))
        return false;

    // Write attributes
    return Animatable::SaveXML(dest);
}

bool Component::SaveJSON(JSONValue& dest) const
{
    // Write type and ID
    dest.Set("type", GetTypeName());
    dest.Set("id", id_);

    // Write attributes
    return Animatable::SaveJSON(dest);
}

void Component::MarkNetworkUpdate()
{
    if (!networkUpdate_ && id_ < FIRST_LOCAL_ID)
    {
        Scene* scene = GetScene();
        if (scene)
        {
            scene->MarkNetworkUpdate(this);
            networkUpdate_ = true;
        }
    }
}

void Component::GetDependencyNodes(PODVector<Node*>& dest)
{
}

void Component::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
{
}

void Component::SetEnabled(bool enable)
{
    if (enable != enabled_)
    {
        enabled_ = enable;
        OnSetEnabled();
        MarkNetworkUpdate();

        // Send change event for the component
        Scene* scene = GetScene();
        if (scene)
        {
            using namespace ComponentEnabledChanged;

            VariantMap& eventData = GetEventDataMap();
            eventData[P_SCENE] = scene;
            eventData[P_NODE] = node_;
            eventData[P_COMPONENT] = this;

            scene->SendEvent(E_COMPONENTENABLEDCHANGED, eventData);
        }
    }
}

void Component::Remove()
{
    if (node_)
        node_->RemoveComponent(this);
}

Scene* Component::GetScene() const
{
    return node_ ? node_->GetScene() : 0;
}

void Component::AddReplicationState(ComponentReplicationState* state)
{
    if (!networkState_)
        AllocateNetworkState();

    networkState_->replicationStates_.Push(state);
}

void Component::PrepareNetworkUpdate()
{
    if (!networkState_)
        AllocateNetworkState();

    const Vector<AttributeInfo>* attributes = networkState_->attributes_;
    if (!attributes)
        return;

    unsigned numAttributes = attributes->Size();

    if (networkState_->currentValues_.Size() != numAttributes)
    {
        networkState_->currentValues_.Resize(numAttributes);
        networkState_->previousValues_.Resize(numAttributes);

        // Copy the default attribute values to the previous state as a starting point
        for (unsigned i = 0; i < numAttributes; ++i)
            networkState_->previousValues_[i] = attributes->At(i).defaultValue_;
    }

    // Check for attribute changes
    for (unsigned i = 0; i < numAttributes; ++i)
    {
        const AttributeInfo& attr = attributes->At(i);

        if (animationEnabled_ && IsAnimatedNetworkAttribute(attr))
            continue;

        OnGetAttribute(attr, networkState_->currentValues_[i]);

        if (networkState_->currentValues_[i] != networkState_->previousValues_[i])
        {
            networkState_->previousValues_[i] = networkState_->currentValues_[i];

            // Mark the attribute dirty in all replication states that are tracking this component
            for (PODVector<ReplicationState*>::Iterator j = networkState_->replicationStates_.Begin();
                 j != networkState_->replicationStates_.End(); ++j)
            {
                ComponentReplicationState* compState = static_cast<ComponentReplicationState*>(*j);
                compState->dirtyAttributes_.Set(i);

                // Add component's parent node to the dirty set if not added yet
                NodeReplicationState* nodeState = compState->nodeState_;
                if (!nodeState->markedDirty_)
                {
                    nodeState->markedDirty_ = true;
                    nodeState->sceneState_->dirtyNodes_.Insert(node_->GetID());
                }
            }
        }
    }

    networkUpdate_ = false;
}

void Component::CleanupConnection(Connection* connection)
{
    if (networkState_)
    {
        for (unsigned i = networkState_->replicationStates_.Size() - 1; i < networkState_->replicationStates_.Size(); --i)
        {
            if (networkState_->replicationStates_[i]->connection_ == connection)
                networkState_->replicationStates_.Erase(i);
        }
    }
}

void Component::OnAttributeAnimationAdded()
{
    if (attributeAnimationInfos_.Size() == 1)
        SubscribeToEvent(GetScene(), E_ATTRIBUTEANIMATIONUPDATE, URHO3D_HANDLER(Component, HandleAttributeAnimationUpdate));
}

void Component::OnAttributeAnimationRemoved()
{
    if (attributeAnimationInfos_.Empty())
        UnsubscribeFromEvent(GetScene(), E_ATTRIBUTEANIMATIONUPDATE);
}

void Component::OnNodeSet(Node* node)
{
}

void Component::OnSceneSet(Scene* scene)
{
}

void Component::OnMarkedDirty(Node* node)
{
}

void Component::OnNodeSetEnabled(Node* node)
{
}

void Component::SetID(unsigned id)
{
    id_ = id;
}

void Component::SetNode(Node* node)
{
    node_ = node;
    OnNodeSet(node_);
}

Component* Component::GetComponent(StringHash type) const
{
    return node_ ? node_->GetComponent(type) : 0;
}

bool Component::IsEnabledEffective() const
{
    return enabled_ && node_ && node_->IsEnabled();
}

void Component::GetComponents(PODVector<Component*>& dest, StringHash type) const
{
    if (node_)
        node_->GetComponents(dest, type);
    else
        dest.Clear();
}

void Component::HandleAttributeAnimationUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace AttributeAnimationUpdate;

    UpdateAttributeAnimations(eventData[P_TIMESTEP].GetFloat());
}

Component* Component::GetFixedUpdateSource()
{
    Component* ret = 0;
    Scene* scene = GetScene();

    if (scene)
    {
#ifdef URHO3D_PHYSICS
        ret = scene->GetComponent<PhysicsWorld>();
#endif
#ifdef URHO3D_URHO2D
        if (!ret)
            ret = scene->GetComponent<PhysicsWorld2D>();
#endif
    }

    return ret;
}

}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/test/auto_test/interface/vie_autotest_android.h"

#include <android/log.h>
#include <stdio.h>

#include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
#include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h"

int ViEAutoTestAndroid::RunAutotest(int testSelection, int subTestSelection,
                                    void* window1, void* window2,
                                    JavaVM* javaVM, void* env, void* context) {
  ViEAutoTest vieAutoTest(window1, window2);
  ViETest::Log("RunAutoTest(%d, %d)", testSelection, subTestSelection);
  webrtc::VideoEngine::SetAndroidObjects(javaVM, context);
#ifndef WEBRTC_ANDROID_OPENSLES
  // voice engine calls into ADM directly
  webrtc::VoiceEngine::SetAndroidObjects(javaVM, env, context);
#endif

  if (subTestSelection == 0) {
    // Run all selected test
    switch (testSelection) {
      case 0:
        vieAutoTest.ViEStandardTest();
        break;
      case 1:
        vieAutoTest.ViEAPITest();
        break;
      case 2:
        vieAutoTest.ViEExtendedTest();
        break;
      case 3:
        vieAutoTest.ViELoopbackCall();
        break;
      default:
        break;
    }
  }

  switch (testSelection) {
    case 0: // Specific standard test
      switch (subTestSelection) {
        case 1: // base
          vieAutoTest.ViEBaseStandardTest();
          break;

        case 2: // capture
          vieAutoTest.ViECaptureStandardTest();
          break;

        case 3: // codec
          vieAutoTest.ViECodecStandardTest();
          break;

        case 6: // image process
          vieAutoTest.ViEImageProcessStandardTest();
          break;

#if 0  // vie_autotest_network.cc isn't actually pulled into the build at all!
        case 7: // network
          vieAutoTest.ViENetworkStandardTest();
          break;
#endif

        case 8: // Render
          vieAutoTest.ViERenderStandardTest();
          break;

        case 9: // RTP/RTCP
          vieAutoTest.ViERtpRtcpStandardTest();
          break;

        default:
          break;
      }
      break;

    case 1:// specific API
      switch (subTestSelection) {
        case 1: // base
          vieAutoTest.ViEBaseAPITest();
          break;

        case 2: // capture
          vieAutoTest.ViECaptureAPITest();
          break;

        case 3: // codec
          vieAutoTest.ViECodecAPITest();
          break;

        case 6: // image process
          vieAutoTest.ViEImageProcessAPITest();
          break;

#if 0  // vie_autotest_network.cc isn't actually pulled into the build at all!
        case 7: // network
          vieAutoTest.ViENetworkAPITest();
          break;
#endif

        case 8: // Render
          vieAutoTest.ViERenderAPITest();
          break;

        case 9: // RTP/RTCP
          vieAutoTest.ViERtpRtcpAPITest();
          break;
        case 10:
          break;

        default:
          break;
      }
      break;

    case 2:// specific extended
      switch (subTestSelection) {
        case 1: // base
          vieAutoTest.ViEBaseExtendedTest();
          break;

        case 2: // capture
          vieAutoTest.ViECaptureExtendedTest();
          break;

        case 3: // codec
          vieAutoTest.ViECodecExtendedTest();
          break;

        case 6: // image process
          vieAutoTest.ViEImageProcessExtendedTest();
          break;

        case 7: // Render
          vieAutoTest.ViERenderExtendedTest();
          break;

        case 8: // RTP/RTCP
          vieAutoTest.ViERtpRtcpExtendedTest();
          break;

        default:
          break;
      }
      break;

    case 3:
      vieAutoTest.ViELoopbackCall();
      break;

    default:
      break;
    }

  return 0;
}

int main(int argc, char** argv) {
  // TODO(leozwang): Add real tests here
  return 0;
}
<commit_msg>ViEAutoTestAndroid: Unbreak compile by casting void* to jobject.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/test/auto_test/interface/vie_autotest_android.h"

#include <android/log.h>
#include <stdio.h>

#include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
#include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h"

int ViEAutoTestAndroid::RunAutotest(int testSelection, int subTestSelection,
                                    void* window1, void* window2,
                                    JavaVM* javaVM, void* env, void* context) {
  ViEAutoTest vieAutoTest(window1, window2);
  ViETest::Log("RunAutoTest(%d, %d)", testSelection, subTestSelection);
  webrtc::VideoEngine::SetAndroidObjects(javaVM, static_cast<jobject>(context));
#ifndef WEBRTC_ANDROID_OPENSLES
  // voice engine calls into ADM directly
  webrtc::VoiceEngine::SetAndroidObjects(javaVM, env, context);
#endif

  if (subTestSelection == 0) {
    // Run all selected test
    switch (testSelection) {
      case 0:
        vieAutoTest.ViEStandardTest();
        break;
      case 1:
        vieAutoTest.ViEAPITest();
        break;
      case 2:
        vieAutoTest.ViEExtendedTest();
        break;
      case 3:
        vieAutoTest.ViELoopbackCall();
        break;
      default:
        break;
    }
  }

  switch (testSelection) {
    case 0: // Specific standard test
      switch (subTestSelection) {
        case 1: // base
          vieAutoTest.ViEBaseStandardTest();
          break;

        case 2: // capture
          vieAutoTest.ViECaptureStandardTest();
          break;

        case 3: // codec
          vieAutoTest.ViECodecStandardTest();
          break;

        case 6: // image process
          vieAutoTest.ViEImageProcessStandardTest();
          break;

#if 0  // vie_autotest_network.cc isn't actually pulled into the build at all!
        case 7: // network
          vieAutoTest.ViENetworkStandardTest();
          break;
#endif

        case 8: // Render
          vieAutoTest.ViERenderStandardTest();
          break;

        case 9: // RTP/RTCP
          vieAutoTest.ViERtpRtcpStandardTest();
          break;

        default:
          break;
      }
      break;

    case 1:// specific API
      switch (subTestSelection) {
        case 1: // base
          vieAutoTest.ViEBaseAPITest();
          break;

        case 2: // capture
          vieAutoTest.ViECaptureAPITest();
          break;

        case 3: // codec
          vieAutoTest.ViECodecAPITest();
          break;

        case 6: // image process
          vieAutoTest.ViEImageProcessAPITest();
          break;

#if 0  // vie_autotest_network.cc isn't actually pulled into the build at all!
        case 7: // network
          vieAutoTest.ViENetworkAPITest();
          break;
#endif

        case 8: // Render
          vieAutoTest.ViERenderAPITest();
          break;

        case 9: // RTP/RTCP
          vieAutoTest.ViERtpRtcpAPITest();
          break;
        case 10:
          break;

        default:
          break;
      }
      break;

    case 2:// specific extended
      switch (subTestSelection) {
        case 1: // base
          vieAutoTest.ViEBaseExtendedTest();
          break;

        case 2: // capture
          vieAutoTest.ViECaptureExtendedTest();
          break;

        case 3: // codec
          vieAutoTest.ViECodecExtendedTest();
          break;

        case 6: // image process
          vieAutoTest.ViEImageProcessExtendedTest();
          break;

        case 7: // Render
          vieAutoTest.ViERenderExtendedTest();
          break;

        case 8: // RTP/RTCP
          vieAutoTest.ViERtpRtcpExtendedTest();
          break;

        default:
          break;
      }
      break;

    case 3:
      vieAutoTest.ViELoopbackCall();
      break;

    default:
      break;
    }

  return 0;
}

int main(int argc, char** argv) {
  // TODO(leozwang): Add real tests here
  return 0;
}
<|endoftext|>