<commit_before>#include <Bull/Utility/Window/Window.hpp>
#include <Bull/Utility/Window/WindowImpl.hpp>

namespace Bull
{
    Window* Window::m_fullscreen = nullptr;

    /*! \brief Get the fullscreen window
     *
     * \return Return a pointer to the window in fullscreen
     *
     */
    const Window* Window::getFullscreen()
    {
        return m_fullscreen;
    }

    /*! \brief Constructor
     *
     * \param mode The VideoMode desired
     * \param title The title of the window
     * \param style The window decoration desired
     *
     */
    Window::Window(const VideoMode& mode, const String& title, Uint32 style)
    {
        open(mode, title, style);
    }

    /*! \brief Open the window. If a window was already opened, its closed
     *
     * \param mode  The VideoMode
     * \param title The title of the window
     * \param style The window decorations
     *
     * \return Return true if the window was open successfully
     *
     */
    bool Window::open(const VideoMode& mode, const String& title, Uint32 style)
    {
        if(isOpen())
        {
            close();
        }

        if(style == Style::Fullscreen && m_fullscreen)
        {
            style = Style::Default;
        }

        m_impl.reset(prv::WindowImpl::createInstance(mode, title, style));

        if(style == Style::Fullscreen)
        {
            enableFullscreen();
        }

        return true;
    }

    /*! \brief Destructor
     *
     */
    Window::~Window()
    {
        close();
    }

    /*! \brief Check if the window is open
     *
     * \return Return true if the window is open, else return false
     *
     */
    bool Window::isOpen() const
    {
        return m_impl.get();
    }

    /*! \brief Close the window
     *
     */
    void Window::close()
    {
        enableCaptureCursor(false);

        if(m_fullscreen == this)
        {
            m_fullscreen = nullptr;
        }

        m_impl.reset();
    }

    /*! \brief Get the first event on the stack without blocking the current thread
     *
     * \param e An event to fill
     *
     * \return Return true if the event stack was not empty, else return false
     *
     */
    bool Window::pollEvent(Event& e)
    {
        if(m_impl)
        {
            bool success = m_impl->popEvent(e, false);

            return success;
        }

        return false;
    }

    /*! \brief Get the first event on the stack and blocking the current thread
     *
     * \return Return the first event of the stack
     *
     */
    Window::Event Window::nextEvent()
    {
        Window::Event e;

        if(m_impl)
        {
            m_impl->popEvent(e, true);
        }

        return e;
    }

    /*! \brief Enable or disable the capture of the cursor inside the window
     *
     * \param enable The state of the capture
     *
     */
    void Window::enableCaptureCursor(bool enable)
    {
        if(m_impl)
        {
            m_impl->enableCaptureCursor(enable);
        }
    }

    /*! \brief Hide or show the cursor
     *
     * \param enable The state of the cursor
     *
     */
    void Window::showCursor(bool enable)
    {
        if(m_impl)
        {
            m_impl->showCursor(enable);
        }
    }

    /*! \brief Minimize a window
     *
     */
    void Window::minimize()
    {
        if(m_impl)
        {
            m_impl->minimize();
        }
    }

    /*! \brief Check if the window is minimized
     *
     * \return Return true if the window is minimized, false otherwise
     *
     */
    bool Window::isMinimized() const
    {
        if(m_impl)
        {
            return m_impl->isMinimized();
        }

        return false;
    }

    /*! \brief Maximize a window
     *
     */
    void Window::maximize()
    {
        if(m_impl)
        {
            m_impl->maximize();
        }
    }

    /*! \brief Check if the window is maximized
     *
     * \return Return true if the window is maximized, false otherwise
     *
     */
    bool Window::isMaximized() const
    {
        if(m_impl)
        {
            return m_impl->isMaximized();
        }

        return false;
    }

    /*! \brief Set the window position
     *
     * \param position The new position of the window
     *
     */
    void Window::setPosition(const Vector2I& position)
    {
        if(m_impl)
        {
            m_impl->setPosition(position);
        }
    }

    /*! \brief Set the window position
     *
     * \param x The new position of the left side of the window in the screen
     * \param y The new position of the top of the window in the screen
     *
     */
    void Window::setPosition(int x, int y)
    {
        setPosition(Vector2I(x, y));
    }

    /*! \brief Get the position in the screen of the window
     *
     * \return Return the window position
     *
     */
    Vector2I Window::getPosition() const
    {
        if(m_impl)
        {
            return m_impl->getPosition();
        }

        return Vector2I();
    }

    /*! \brief Set the size of the window
     *
     * \param size The new size of the window
     *
     */
    void Window::setSize(const Vector2UI& size)
    {
        if(m_impl)
        {
            m_impl->setSize(size);
        }
    }

    /*! \brief Set the size of the window
     *
     * \param size The new size of the window
     *
     */
    void Window::setSize(unsigned int x, unsigned int y)
    {
        m_impl->setSize(Vector2UI(x, y));
    }

    /*! \brief Set the size of the window
     *
     * \param x The new width of the window
     * \param y The new height of the window
     *
     */
    Vector2UI Window::getSize() const
    {
        if(m_impl)
        {
            return m_impl->getSize();
        }

        return Vector2UI();
    }

    /*! \brief Set the title of the window
     *
     * \param title The new title of the window
     *
     */
    void Window::setTitle(const String& title)
    {
        if(m_impl)
        {
            m_impl->setTitle(title);
        }
    }

    /*! \brief Get the title of the window
     *
     * \return Return the title of the window
     *
     */
    String Window::getTitle() const
    {
        if(m_impl)
        {
            return m_impl->getTitle();
        }

        return String();
    }

    /*! \brief Enable or disable the key repeat
     *
     * \param enable The state of the key repeat
     *
     */
    void Window::enableKeyRepeat(bool enable)
    {
        if(m_impl)
        {
            m_impl->enableKeyRepeat(enable);
        }
    }

    /*! \brief Get the state of the key repeat
     *
     * \param Return true if the key repeat is enable, false otherwise
     *
     */
    bool Window::isKeyRepeatEnable() const
    {
        if(m_impl)
        {
            return m_impl->isKeyRepeatEnable();
        }

        return false;
    }

    /*! \brief Check if the window has the focus
     *
     * \param Return true if the window has the focus, false otherwise
     *
     */
    bool Window::hasFocus() const
    {
        if(m_impl)
        {
            return m_impl->hasFocus();
        }

        return false;
    }

    /*! \brief Show or hide the window
     *
     * \param visible True to show the window, false to hide the window
     *
     */
    void Window::setVisible(bool visible)
    {
        if(m_impl)
        {
            m_impl->setVisible(visible);
        }
    }

    /*! \brief Enter or leave the fullscreen mode
     *
     * \param fullscreen False to leave the fullscreen mode, true to enter the fullscreen mode
     *
     * \return Return true if the switch was done successfully, false otherwise
     *
     */
    bool Window::enableFullscreen(bool fullscreen)
    {
        if(m_impl && (!fullscreen || fullscreen && !m_fullscreen))
        {
            m_impl->switchFullscreen(fullscreen);

            if(fullscreen)
            {
                m_fullscreen = this;
                enableCaptureCursor();
            }
            else
            {
                enableCaptureCursor(false);
                m_fullscreen = nullptr;
            }

            return true;
        }

        return false;
    }

    /*! \brief Check whether the window is in fullscreen
     *
     * \return Return true if the window is in fullscreen, false otherwise
     *
     */
    bool Window::isFullscreenEnable() const
    {
        return this == m_fullscreen;
    }

    /*! \brief Get the window system handler
     *
     * \return Return the native window system handler
     *
     */
    WindowHandler Window::getSystemHandler() const
    {
        if(m_impl)
        {
            return m_impl->getSystemHandler();
        }

        return 0;
    }
}
<commit_msg>[Utility/Window] Fix warning<commit_after>#include <Bull/Utility/Window/Window.hpp>
#include <Bull/Utility/Window/WindowImpl.hpp>

namespace Bull
{
    Window* Window::m_fullscreen = nullptr;

    /*! \brief Get the fullscreen window
     *
     * \return Return a pointer to the window in fullscreen
     *
     */
    const Window* Window::getFullscreen()
    {
        return m_fullscreen;
    }

    /*! \brief Constructor
     *
     * \param mode The VideoMode desired
     * \param title The title of the window
     * \param style The window decoration desired
     *
     */
    Window::Window(const VideoMode& mode, const String& title, Uint32 style)
    {
        open(mode, title, style);
    }

    /*! \brief Open the window. If a window was already opened, its closed
     *
     * \param mode  The VideoMode
     * \param title The title of the window
     * \param style The window decorations
     *
     * \return Return true if the window was open successfully
     *
     */
    bool Window::open(const VideoMode& mode, const String& title, Uint32 style)
    {
        if(isOpen())
        {
            close();
        }

        if(style == Style::Fullscreen && m_fullscreen)
        {
            style = Style::Default;
        }

        m_impl.reset(prv::WindowImpl::createInstance(mode, title, style));

        if(style == Style::Fullscreen)
        {
            enableFullscreen();
        }

        return true;
    }

    /*! \brief Destructor
     *
     */
    Window::~Window()
    {
        close();
    }

    /*! \brief Check if the window is open
     *
     * \return Return true if the window is open, else return false
     *
     */
    bool Window::isOpen() const
    {
        return m_impl.get();
    }

    /*! \brief Close the window
     *
     */
    void Window::close()
    {
        enableCaptureCursor(false);

        if(m_fullscreen == this)
        {
            m_fullscreen = nullptr;
        }

        m_impl.reset();
    }

    /*! \brief Get the first event on the stack without blocking the current thread
     *
     * \param e An event to fill
     *
     * \return Return true if the event stack was not empty, else return false
     *
     */
    bool Window::pollEvent(Event& e)
    {
        if(m_impl)
        {
            bool success = m_impl->popEvent(e, false);

            return success;
        }

        return false;
    }

    /*! \brief Get the first event on the stack and blocking the current thread
     *
     * \return Return the first event of the stack
     *
     */
    Window::Event Window::nextEvent()
    {
        Window::Event e;

        if(m_impl)
        {
            m_impl->popEvent(e, true);
        }

        return e;
    }

    /*! \brief Enable or disable the capture of the cursor inside the window
     *
     * \param enable The state of the capture
     *
     */
    void Window::enableCaptureCursor(bool enable)
    {
        if(m_impl)
        {
            m_impl->enableCaptureCursor(enable);
        }
    }

    /*! \brief Hide or show the cursor
     *
     * \param enable The state of the cursor
     *
     */
    void Window::showCursor(bool enable)
    {
        if(m_impl)
        {
            m_impl->showCursor(enable);
        }
    }

    /*! \brief Minimize a window
     *
     */
    void Window::minimize()
    {
        if(m_impl)
        {
            m_impl->minimize();
        }
    }

    /*! \brief Check if the window is minimized
     *
     * \return Return true if the window is minimized, false otherwise
     *
     */
    bool Window::isMinimized() const
    {
        if(m_impl)
        {
            return m_impl->isMinimized();
        }

        return false;
    }

    /*! \brief Maximize a window
     *
     */
    void Window::maximize()
    {
        if(m_impl)
        {
            m_impl->maximize();
        }
    }

    /*! \brief Check if the window is maximized
     *
     * \return Return true if the window is maximized, false otherwise
     *
     */
    bool Window::isMaximized() const
    {
        if(m_impl)
        {
            return m_impl->isMaximized();
        }

        return false;
    }

    /*! \brief Set the window position
     *
     * \param position The new position of the window
     *
     */
    void Window::setPosition(const Vector2I& position)
    {
        if(m_impl)
        {
            m_impl->setPosition(position);
        }
    }

    /*! \brief Set the window position
     *
     * \param x The new position of the left side of the window in the screen
     * \param y The new position of the top of the window in the screen
     *
     */
    void Window::setPosition(int x, int y)
    {
        setPosition(Vector2I(x, y));
    }

    /*! \brief Get the position in the screen of the window
     *
     * \return Return the window position
     *
     */
    Vector2I Window::getPosition() const
    {
        if(m_impl)
        {
            return m_impl->getPosition();
        }

        return Vector2I();
    }

    /*! \brief Set the size of the window
     *
     * \param size The new size of the window
     *
     */
    void Window::setSize(const Vector2UI& size)
    {
        if(m_impl)
        {
            m_impl->setSize(size);
        }
    }

    /*! \brief Set the size of the window
     *
     * \param size The new size of the window
     *
     */
    void Window::setSize(unsigned int x, unsigned int y)
    {
        m_impl->setSize(Vector2UI(x, y));
    }

    /*! \brief Set the size of the window
     *
     * \param x The new width of the window
     * \param y The new height of the window
     *
     */
    Vector2UI Window::getSize() const
    {
        if(m_impl)
        {
            return m_impl->getSize();
        }

        return Vector2UI();
    }

    /*! \brief Set the title of the window
     *
     * \param title The new title of the window
     *
     */
    void Window::setTitle(const String& title)
    {
        if(m_impl)
        {
            m_impl->setTitle(title);
        }
    }

    /*! \brief Get the title of the window
     *
     * \return Return the title of the window
     *
     */
    String Window::getTitle() const
    {
        if(m_impl)
        {
            return m_impl->getTitle();
        }

        return String();
    }

    /*! \brief Enable or disable the key repeat
     *
     * \param enable The state of the key repeat
     *
     */
    void Window::enableKeyRepeat(bool enable)
    {
        if(m_impl)
        {
            m_impl->enableKeyRepeat(enable);
        }
    }

    /*! \brief Get the state of the key repeat
     *
     * \param Return true if the key repeat is enable, false otherwise
     *
     */
    bool Window::isKeyRepeatEnable() const
    {
        if(m_impl)
        {
            return m_impl->isKeyRepeatEnable();
        }

        return false;
    }

    /*! \brief Check if the window has the focus
     *
     * \param Return true if the window has the focus, false otherwise
     *
     */
    bool Window::hasFocus() const
    {
        if(m_impl)
        {
            return m_impl->hasFocus();
        }

        return false;
    }

    /*! \brief Show or hide the window
     *
     * \param visible True to show the window, false to hide the window
     *
     */
    void Window::setVisible(bool visible)
    {
        if(m_impl)
        {
            m_impl->setVisible(visible);
        }
    }

    /*! \brief Enter or leave the fullscreen mode
     *
     * \param fullscreen False to leave the fullscreen mode, true to enter the fullscreen mode
     *
     * \return Return true if the switch was done successfully, false otherwise
     *
     */
    bool Window::enableFullscreen(bool fullscreen)
    {
        if(m_impl && (!fullscreen || (fullscreen && !m_fullscreen)))
        {
            m_impl->switchFullscreen(fullscreen);

            if(fullscreen)
            {
                m_fullscreen = this;
                enableCaptureCursor();
            }
            else
            {
                enableCaptureCursor(false);
                m_fullscreen = nullptr;
            }

            return true;
        }

        return false;
    }

    /*! \brief Check whether the window is in fullscreen
     *
     * \return Return true if the window is in fullscreen, false otherwise
     *
     */
    bool Window::isFullscreenEnable() const
    {
        return this == m_fullscreen;
    }

    /*! \brief Get the window system handler
     *
     * \return Return the native window system handler
     *
     */
    WindowHandler Window::getSystemHandler() const
    {
        if(m_impl)
        {
            return m_impl->getSystemHandler();
        }

        return 0;
    }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * standardpanel.cpp : The "standard" playlist panel : just a treeview
 ****************************************************************************
 * Copyright (C) 2000-2005 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "qt4.hpp"
#include "dialogs_provider.hpp"
#include "components/playlist/playlist_model.hpp"
#include "components/playlist/panels.hpp"
#include "util/customwidgets.hpp"

#include <vlc_intf_strings.h>

#include <QTreeView>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QHeaderView>
#include <QKeyEvent>
#include <QModelIndexList>
#include <QToolBar>
#include <QLabel>
#include <QSpacerItem>
#include <QMenu>
#include <QSignalMapper>

#include <assert.h>

StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
                                  intf_thread_t *_p_intf,
                                  playlist_t *p_playlist,
                                  playlist_item_t *p_root ):
                                  PLPanel( _parent, _p_intf )
{
    model = new PLModel( p_playlist, p_intf, p_root, -1, this );

    QVBoxLayout *layout = new QVBoxLayout();
    layout->setSpacing( 0 ); layout->setMargin( 0 );

    /* Create and configure the QTreeView */
    view = new QVLCTreeView( 0 );
    view->setModel(model);
    view->setIconSize( QSize( 20, 20 ) );
    view->setAlternatingRowColors( true );
    view->setAnimated( true );
    view->setSortingEnabled( true );
    view->setSelectionMode( QAbstractItemView::ExtendedSelection );
    view->setDragEnabled( true );
    view->setAcceptDrops( true );
    view->setDropIndicatorShown( true );
    view->setAutoScroll( true );

    /* Configure the size of the header */
    view->header()->resizeSection( 0, 200 );
    view->header()->resizeSection( 1, 80 );
    view->header()->setSortIndicatorShown( true );
    view->header()->setClickable( true );
    view->header()->setContextMenuPolicy( Qt::CustomContextMenu );

    /* Connections for the TreeView */
    CONNECT( view, activated( const QModelIndex& ) ,
             model,activateItem( const QModelIndex& ) );
    CONNECT( view, rightClicked( QModelIndex , QPoint ),
             this, doPopup( QModelIndex, QPoint ) );
    CONNECT( model, dataChanged( const QModelIndex&, const QModelIndex& ),
             this, handleExpansion( const QModelIndex& ) );
    CONNECT( view->header(), customContextMenuRequested( const QPoint & ),
             this, popupSelectColumn( QPoint ) );

    currentRootId = -1;
    CONNECT( parent, rootChanged( int ), this, setCurrentRootId( int ) );

    /* Buttons configuration */
    QHBoxLayout *buttons = new QHBoxLayout;

    /* Add item to the playlist button */
    addButton = new QPushButton;
    addButton->setIcon( QIcon( ":/pixmaps/playlist_add.png" ) );
    addButton->setMaximumWidth( 30 );
    BUTTONACT( addButton, popupAdd() );
    buttons->addWidget( addButton );

    /* Random 2-state button */
    randomButton = new QPushButton( this );
    if( model->hasRandom() )
    {
        randomButton->setIcon( QIcon( ":/pixmaps/playlist_shuffle_on.png" ));
        randomButton->setToolTip( qtr( I_PL_RANDOM ));
    }
    else
    {
         randomButton->setIcon( QIcon( ":/pixmaps/playlist_shuffle_off.png" ) );
         randomButton->setToolTip( qtr( I_PL_NORANDOM ));
    }
    BUTTONACT( randomButton, toggleRandom() );
    buttons->addWidget( randomButton );

    /* Repeat 3-state button */
    repeatButton = new QPushButton( this );
    if( model->hasRepeat() )
    {
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_one.png" ) );
        repeatButton->setToolTip( qtr( I_PL_REPEAT ));
    }
    else if( model->hasLoop() )
    {
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_all.png" ) );
        repeatButton->setToolTip( qtr( I_PL_LOOP ));
    }
    else
    {
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_off.png" ) );
        repeatButton->setToolTip( qtr( I_PL_NOREPEAT ));
    }
    BUTTONACT( repeatButton, toggleRepeat() );
    buttons->addWidget( repeatButton );

    /* Goto */
    gotoPlayingButton = new QPushButton( "X" , this );
    gotoPlayingButton->setToolTip( qtr( "Show the current item" ));
    BUTTONACT( gotoPlayingButton, gotoPlayingItem() );
    buttons->addWidget( gotoPlayingButton );

    /* A Spacer and the search possibilities */
    QSpacerItem *spacer = new QSpacerItem( 10, 20 );
    buttons->addItem( spacer );

    QLabel *filter = new QLabel( qtr(I_PL_SEARCH) + " " );
    buttons->addWidget( filter );

    searchLine = new  ClickLineEdit( qtr(I_PL_FILTER), 0 );
    searchLine->setMinimumWidth( 80 );
    CONNECT( searchLine, textChanged(QString), this, search(QString));
    buttons->addWidget( searchLine ); filter->setBuddy( searchLine );

    QPushButton *clear = new QPushButton;
    clear->setText( qfu( "CL") );
    clear->setMaximumWidth( 30 );
    clear->setToolTip( qtr( "Clear" ));
    BUTTONACT( clear, clearFilter() );
    buttons->addWidget( clear );

    /* Finish the layout */
    layout->addWidget( view );
    layout->addLayout( buttons );
//    layout->addWidget( bar );
    setLayout( layout );
}

/* Function to toggle between the Repeat states */
void StandardPLPanel::toggleRepeat()
{
    if( model->hasRepeat() )
    {
        model->setRepeat( false ); model->setLoop( true );
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_all.png" ) );
        repeatButton->setToolTip( qtr( I_PL_LOOP ));
    }
    else if( model->hasLoop() )
    {
        model->setRepeat( false ) ; model->setLoop( false );
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_off.png" ) );
        repeatButton->setToolTip( qtr( I_PL_NOREPEAT ));
    }
    else
    {
        model->setRepeat( true );
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_one.png" ) );
        repeatButton->setToolTip( qtr( I_PL_REPEAT ));
    }
}

/* Function to toggle between the Random states */
void StandardPLPanel::toggleRandom()
{
    bool prev = model->hasRandom();
    model->setRandom( !prev );
    randomButton->setIcon( prev ?
                QIcon( ":/pixmaps/playlist_shuffle_off.png" ) :
                QIcon( ":/pixmaps/playlist_shuffle_on.png" ) );
    randomButton->setToolTip( prev ? qtr( I_PL_NORANDOM ) : qtr(I_PL_RANDOM ) );
}

void StandardPLPanel::gotoPlayingItem()
{
    view->scrollTo( view->currentIndex() );
}

void StandardPLPanel::handleExpansion( const QModelIndex &index )
{
    if( model->isCurrent( index ) )
        view->scrollTo( index, QAbstractItemView::EnsureVisible );
}

void StandardPLPanel::setCurrentRootId( int _new )
{
    currentRootId = _new;
    if( currentRootId == THEPL->p_local_category->i_id ||
        currentRootId == THEPL->p_local_onelevel->i_id  )
    {
        addButton->setEnabled( true );
        addButton->setToolTip( qtr(I_PL_ADDPL) );
    }
    else if( ( THEPL->p_ml_category &&
                        currentRootId == THEPL->p_ml_category->i_id ) ||
             ( THEPL->p_ml_onelevel &&
                        currentRootId == THEPL->p_ml_onelevel->i_id ) )
    {
        addButton->setEnabled( true );
        addButton->setToolTip( qtr(I_PL_ADDML) );
    }
    else
        addButton->setEnabled( false );
}

/* PopupAdd Menu for the Add Menu */
void StandardPLPanel::popupAdd()
{
    QMenu popup;
    if( currentRootId == THEPL->p_local_category->i_id ||
        currentRootId == THEPL->p_local_onelevel->i_id )
    {
        popup.addAction( qtr(I_PL_ADDF), THEDP, SLOT(simplePLAppendDialog()));
        popup.addAction( qtr(I_PL_ADVADD), THEDP, SLOT(PLAppendDialog()) );
        popup.addAction( qtr(I_PL_ADDDIR), THEDP, SLOT( PLAppendDir()) );
    }
    else if( ( THEPL->p_ml_category &&
                currentRootId == THEPL->p_ml_category->i_id ) ||
             ( THEPL->p_ml_onelevel &&
                currentRootId == THEPL->p_ml_onelevel->i_id ) )
    {
        popup.addAction( qtr(I_PL_ADDF), THEDP, SLOT(simpleMLAppendDialog()));
        popup.addAction( qtr(I_PL_ADVADD), THEDP, SLOT( MLAppendDialog() ) );
        popup.addAction( qtr(I_PL_ADDDIR), THEDP, SLOT( MLAppendDir() ) );
    }
    popup.exec( QCursor::pos() - addButton->mapFromGlobal( QCursor::pos() )
                        + QPoint( 0, addButton->height() ) );
}

void StandardPLPanel::popupSelectColumn( QPoint pos )
{
    ContextUpdateMapper = new QSignalMapper(this);

    QMenu selectColMenu;

#define ADD_META_ACTION( meta ) { \
    QAction* option = selectColMenu.addAction( qfu(VLC_META_##meta) );      \
    option->setCheckable( true );                                           \
    option->setChecked( model->shownFlags() & VLC_META_ENGINE_##meta );     \
    ContextUpdateMapper->setMapping( option, VLC_META_ENGINE_##meta );      \
    CONNECT( option, triggered(), ContextUpdateMapper, map() );             \
}

    CONNECT( ContextUpdateMapper, mapped( int ),  model, viewchanged( int ) );

    ADD_META_ACTION( TRACKID );
    ADD_META_ACTION( TITLE );
    ADD_META_ACTION( DURATION );
    ADD_META_ACTION( ARTIST );
    ADD_META_ACTION( GENRE );
    ADD_META_ACTION( COLLECTION );
    ADD_META_ACTION( SEQ_NUM );
    ADD_META_ACTION( DESCRIPTION );

#undef ADD_META_ACTION

    selectColMenu.exec( QCursor::pos() );
}

/* ClearFilter LineEdit */
void StandardPLPanel::clearFilter()
{
    searchLine->setText( "" );
}

/* Search in the playlist */
void StandardPLPanel::search( QString searchText )
{
    model->search( searchText );
}

void StandardPLPanel::doPopup( QModelIndex index, QPoint point )
{
    if( !index.isValid() ) return;
    QItemSelectionModel *selection = view->selectionModel();
    QModelIndexList list = selection->selectedIndexes();
    model->popup( index, point, list );
}

/* Set the root of the new Playlist */
/* This activated by the selector selection */
void StandardPLPanel::setRoot( int i_root_id )
{
    playlist_item_t *p_item = playlist_ItemGetById( THEPL, i_root_id,
                                                    VLC_TRUE );
    assert( p_item );
    p_item = playlist_GetPreferredNode( THEPL, p_item );
    assert( p_item );
    model->rebuild( p_item );
}

void StandardPLPanel::removeItem( int i_id )
{
    model->removeItem( i_id );
}

/* Delete and Suppr key remove the selection
   FilterKey function and code function */
void StandardPLPanel::keyPressEvent( QKeyEvent *e )
{
    switch( e->key() )
    {
    case Qt::Key_Back:
    case Qt::Key_Delete:
        deleteSelection();
        break;
    }
}

void StandardPLPanel::deleteSelection()
{
    QItemSelectionModel *selection = view->selectionModel();
    QModelIndexList list = selection->selectedIndexes();
    model->doDelete( list );
}

StandardPLPanel::~StandardPLPanel()
{}
<commit_msg>Turn off sorting on startup fix of #1529<commit_after>/*****************************************************************************
 * standardpanel.cpp : The "standard" playlist panel : just a treeview
 ****************************************************************************
 * Copyright (C) 2000-2005 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "qt4.hpp"
#include "dialogs_provider.hpp"
#include "components/playlist/playlist_model.hpp"
#include "components/playlist/panels.hpp"
#include "util/customwidgets.hpp"

#include <vlc_intf_strings.h>

#include <QTreeView>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QHeaderView>
#include <QKeyEvent>
#include <QModelIndexList>
#include <QToolBar>
#include <QLabel>
#include <QSpacerItem>
#include <QMenu>
#include <QSignalMapper>

#include <assert.h>

StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
                                  intf_thread_t *_p_intf,
                                  playlist_t *p_playlist,
                                  playlist_item_t *p_root ):
                                  PLPanel( _parent, _p_intf )
{
    model = new PLModel( p_playlist, p_intf, p_root, -1, this );

    QVBoxLayout *layout = new QVBoxLayout();
    layout->setSpacing( 0 ); layout->setMargin( 0 );

    /* Create and configure the QTreeView */
    view = new QVLCTreeView( 0 );
    view->setSortingEnabled( true );
    view->sortByColumn( -1, Qt::AscendingOrder );
    view->setModel(model);
    view->setIconSize( QSize( 20, 20 ) );
    view->setAlternatingRowColors( true );
    view->setAnimated( true );
    view->setSelectionMode( QAbstractItemView::ExtendedSelection );
    view->setDragEnabled( true );
    view->setAcceptDrops( true );
    view->setDropIndicatorShown( true );
    view->setAutoScroll( true );

    /* Configure the size of the header */
    view->header()->resizeSection( 0, 200 );
    view->header()->resizeSection( 1, 80 );
    view->header()->setSortIndicatorShown( true );
    view->header()->setClickable( true );
    view->header()->setContextMenuPolicy( Qt::CustomContextMenu );

    /* Connections for the TreeView */
    CONNECT( view, activated( const QModelIndex& ) ,
             model,activateItem( const QModelIndex& ) );
    CONNECT( view, rightClicked( QModelIndex , QPoint ),
             this, doPopup( QModelIndex, QPoint ) );
    CONNECT( model, dataChanged( const QModelIndex&, const QModelIndex& ),
             this, handleExpansion( const QModelIndex& ) );
    CONNECT( view->header(), customContextMenuRequested( const QPoint & ),
             this, popupSelectColumn( QPoint ) );

    currentRootId = -1;
    CONNECT( parent, rootChanged( int ), this, setCurrentRootId( int ) );

    /* Buttons configuration */
    QHBoxLayout *buttons = new QHBoxLayout;

    /* Add item to the playlist button */
    addButton = new QPushButton;
    addButton->setIcon( QIcon( ":/pixmaps/playlist_add.png" ) );
    addButton->setMaximumWidth( 30 );
    BUTTONACT( addButton, popupAdd() );
    buttons->addWidget( addButton );

    /* Random 2-state button */
    randomButton = new QPushButton( this );
    if( model->hasRandom() )
    {
        randomButton->setIcon( QIcon( ":/pixmaps/playlist_shuffle_on.png" ));
        randomButton->setToolTip( qtr( I_PL_RANDOM ));
    }
    else
    {
         randomButton->setIcon( QIcon( ":/pixmaps/playlist_shuffle_off.png" ) );
         randomButton->setToolTip( qtr( I_PL_NORANDOM ));
    }
    BUTTONACT( randomButton, toggleRandom() );
    buttons->addWidget( randomButton );

    /* Repeat 3-state button */
    repeatButton = new QPushButton( this );
    if( model->hasRepeat() )
    {
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_one.png" ) );
        repeatButton->setToolTip( qtr( I_PL_REPEAT ));
    }
    else if( model->hasLoop() )
    {
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_all.png" ) );
        repeatButton->setToolTip( qtr( I_PL_LOOP ));
    }
    else
    {
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_off.png" ) );
        repeatButton->setToolTip( qtr( I_PL_NOREPEAT ));
    }
    BUTTONACT( repeatButton, toggleRepeat() );
    buttons->addWidget( repeatButton );

    /* Goto */
    gotoPlayingButton = new QPushButton( "X" , this );
    gotoPlayingButton->setToolTip( qtr( "Show the current item" ));
    BUTTONACT( gotoPlayingButton, gotoPlayingItem() );
    buttons->addWidget( gotoPlayingButton );

    /* A Spacer and the search possibilities */
    QSpacerItem *spacer = new QSpacerItem( 10, 20 );
    buttons->addItem( spacer );

    QLabel *filter = new QLabel( qtr(I_PL_SEARCH) + " " );
    buttons->addWidget( filter );

    searchLine = new  ClickLineEdit( qtr(I_PL_FILTER), 0 );
    searchLine->setMinimumWidth( 80 );
    CONNECT( searchLine, textChanged(QString), this, search(QString));
    buttons->addWidget( searchLine ); filter->setBuddy( searchLine );

    QPushButton *clear = new QPushButton;
    clear->setText( qfu( "CL") );
    clear->setMaximumWidth( 30 );
    clear->setToolTip( qtr( "Clear" ));
    BUTTONACT( clear, clearFilter() );
    buttons->addWidget( clear );

    /* Finish the layout */
    layout->addWidget( view );
    layout->addLayout( buttons );
//    layout->addWidget( bar );
    setLayout( layout );
}

/* Function to toggle between the Repeat states */
void StandardPLPanel::toggleRepeat()
{
    if( model->hasRepeat() )
    {
        model->setRepeat( false ); model->setLoop( true );
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_all.png" ) );
        repeatButton->setToolTip( qtr( I_PL_LOOP ));
    }
    else if( model->hasLoop() )
    {
        model->setRepeat( false ) ; model->setLoop( false );
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_off.png" ) );
        repeatButton->setToolTip( qtr( I_PL_NOREPEAT ));
    }
    else
    {
        model->setRepeat( true );
        repeatButton->setIcon( QIcon( ":/pixmaps/playlist_repeat_one.png" ) );
        repeatButton->setToolTip( qtr( I_PL_REPEAT ));
    }
}

/* Function to toggle between the Random states */
void StandardPLPanel::toggleRandom()
{
    bool prev = model->hasRandom();
    model->setRandom( !prev );
    randomButton->setIcon( prev ?
                QIcon( ":/pixmaps/playlist_shuffle_off.png" ) :
                QIcon( ":/pixmaps/playlist_shuffle_on.png" ) );
    randomButton->setToolTip( prev ? qtr( I_PL_NORANDOM ) : qtr(I_PL_RANDOM ) );
}

void StandardPLPanel::gotoPlayingItem()
{
    view->scrollTo( view->currentIndex() );
}

void StandardPLPanel::handleExpansion( const QModelIndex &index )
{
    if( model->isCurrent( index ) )
        view->scrollTo( index, QAbstractItemView::EnsureVisible );
}

void StandardPLPanel::setCurrentRootId( int _new )
{
    currentRootId = _new;
    if( currentRootId == THEPL->p_local_category->i_id ||
        currentRootId == THEPL->p_local_onelevel->i_id  )
    {
        addButton->setEnabled( true );
        addButton->setToolTip( qtr(I_PL_ADDPL) );
    }
    else if( ( THEPL->p_ml_category &&
                        currentRootId == THEPL->p_ml_category->i_id ) ||
             ( THEPL->p_ml_onelevel &&
                        currentRootId == THEPL->p_ml_onelevel->i_id ) )
    {
        addButton->setEnabled( true );
        addButton->setToolTip( qtr(I_PL_ADDML) );
    }
    else
        addButton->setEnabled( false );
}

/* PopupAdd Menu for the Add Menu */
void StandardPLPanel::popupAdd()
{
    QMenu popup;
    if( currentRootId == THEPL->p_local_category->i_id ||
        currentRootId == THEPL->p_local_onelevel->i_id )
    {
        popup.addAction( qtr(I_PL_ADDF), THEDP, SLOT(simplePLAppendDialog()));
        popup.addAction( qtr(I_PL_ADVADD), THEDP, SLOT(PLAppendDialog()) );
        popup.addAction( qtr(I_PL_ADDDIR), THEDP, SLOT( PLAppendDir()) );
    }
    else if( ( THEPL->p_ml_category &&
                currentRootId == THEPL->p_ml_category->i_id ) ||
             ( THEPL->p_ml_onelevel &&
                currentRootId == THEPL->p_ml_onelevel->i_id ) )
    {
        popup.addAction( qtr(I_PL_ADDF), THEDP, SLOT(simpleMLAppendDialog()));
        popup.addAction( qtr(I_PL_ADVADD), THEDP, SLOT( MLAppendDialog() ) );
        popup.addAction( qtr(I_PL_ADDDIR), THEDP, SLOT( MLAppendDir() ) );
    }
    popup.exec( QCursor::pos() - addButton->mapFromGlobal( QCursor::pos() )
                        + QPoint( 0, addButton->height() ) );
}

void StandardPLPanel::popupSelectColumn( QPoint pos )
{
    ContextUpdateMapper = new QSignalMapper(this);

    QMenu selectColMenu;

#define ADD_META_ACTION( meta ) { \
    QAction* option = selectColMenu.addAction( qfu(VLC_META_##meta) );      \
    option->setCheckable( true );                                           \
    option->setChecked( model->shownFlags() & VLC_META_ENGINE_##meta );     \
    ContextUpdateMapper->setMapping( option, VLC_META_ENGINE_##meta );      \
    CONNECT( option, triggered(), ContextUpdateMapper, map() );             \
}

    CONNECT( ContextUpdateMapper, mapped( int ),  model, viewchanged( int ) );

    ADD_META_ACTION( TRACKID );
    ADD_META_ACTION( TITLE );
    ADD_META_ACTION( DURATION );
    ADD_META_ACTION( ARTIST );
    ADD_META_ACTION( GENRE );
    ADD_META_ACTION( COLLECTION );
    ADD_META_ACTION( SEQ_NUM );
    ADD_META_ACTION( DESCRIPTION );

#undef ADD_META_ACTION

    selectColMenu.exec( QCursor::pos() );
}

/* ClearFilter LineEdit */
void StandardPLPanel::clearFilter()
{
    searchLine->setText( "" );
}

/* Search in the playlist */
void StandardPLPanel::search( QString searchText )
{
    model->search( searchText );
}

void StandardPLPanel::doPopup( QModelIndex index, QPoint point )
{
    if( !index.isValid() ) return;
    QItemSelectionModel *selection = view->selectionModel();
    QModelIndexList list = selection->selectedIndexes();
    model->popup( index, point, list );
}

/* Set the root of the new Playlist */
/* This activated by the selector selection */
void StandardPLPanel::setRoot( int i_root_id )
{
    playlist_item_t *p_item = playlist_ItemGetById( THEPL, i_root_id,
                                                    VLC_TRUE );
    assert( p_item );
    p_item = playlist_GetPreferredNode( THEPL, p_item );
    assert( p_item );
    model->rebuild( p_item );
}

void StandardPLPanel::removeItem( int i_id )
{
    model->removeItem( i_id );
}

/* Delete and Suppr key remove the selection
   FilterKey function and code function */
void StandardPLPanel::keyPressEvent( QKeyEvent *e )
{
    switch( e->key() )
    {
    case Qt::Key_Back:
    case Qt::Key_Delete:
        deleteSelection();
        break;
    }
}

void StandardPLPanel::deleteSelection()
{
    QItemSelectionModel *selection = view->selectionModel();
    QModelIndexList list = selection->selectedIndexes();
    model->doDelete( list );
}

StandardPLPanel::~StandardPLPanel()
{}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

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

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @file ControlFlowGraph.cpp
 * @author Christian <c@ethdev.com>
 * @date 2015
 * Control flow analysis for the optimizer.
 */

#include <libevmasm/ControlFlowGraph.h>
#include <map>
#include <memory>
#include <algorithm>
#include <libevmasm/Exceptions.h>
#include <libevmasm/AssemblyItem.h>
#include <libevmasm/SemanticInformation.h>
#include <libevmasm/KnownState.h>

using namespace std;
using namespace dev;
using namespace dev::eth;

BlockId::BlockId(u256 const& _id):
	m_id(unsigned(_id))
{
	assertThrow( _id < initial().m_id, OptimizerException, "Tag number too large.");
}

BasicBlocks ControlFlowGraph::optimisedBlocks()
{
	if (m_items.empty())
		return BasicBlocks();

	findLargestTag();
	splitBlocks();
	resolveNextLinks();
	removeUnusedBlocks();
	setPrevLinks();
	gatherKnowledge();

	return rebuildCode();
}

void ControlFlowGraph::findLargestTag()
{
	m_lastUsedId = 0;
	for (auto const& item: m_items)
		if (item.type() == Tag || item.type() == PushTag)
		{
			// Assert that it can be converted.
			BlockId(item.data());
			m_lastUsedId = max(unsigned(item.data()), m_lastUsedId);
		}
}

void ControlFlowGraph::splitBlocks()
{
	m_blocks.clear();
	BlockId id = BlockId::initial();
	m_blocks[id].begin = 0;
	for (size_t index = 0; index < m_items.size(); ++index)
	{
		AssemblyItem const& item = m_items.at(index);
		if (item.type() == Tag)
		{
			if (id)
				m_blocks[id].end = index;
			id = BlockId::invalid();
		}
		if (!id)
		{
			id = item.type() == Tag ? BlockId(item.data()) : generateNewId();
			m_blocks[id].begin = index;
		}
		if (item.type() == PushTag)
			m_blocks[id].pushedTags.push_back(BlockId(item.data()));
		if (SemanticInformation::altersControlFlow(item))
		{
			m_blocks[id].end = index + 1;
			if (item == Instruction::JUMP)
				m_blocks[id].endType = BasicBlock::EndType::JUMP;
			else if (item == Instruction::JUMPI)
				m_blocks[id].endType = BasicBlock::EndType::JUMPI;
			else
				m_blocks[id].endType = BasicBlock::EndType::STOP;
			id = BlockId::invalid();
		}
	}
	if (id)
	{
		m_blocks[id].end = m_items.size();
		if (m_blocks[id].endType == BasicBlock::EndType::HANDOVER)
			m_blocks[id].endType = BasicBlock::EndType::STOP;
	}
}

void ControlFlowGraph::resolveNextLinks()
{
	map<unsigned, BlockId> blockByBeginPos;
	for (auto const& idAndBlock: m_blocks)
		if (idAndBlock.second.begin != idAndBlock.second.end)
			blockByBeginPos[idAndBlock.second.begin] = idAndBlock.first;

	for (auto& idAndBlock: m_blocks)
	{
		BasicBlock& block = idAndBlock.second;
		switch (block.endType)
		{
		case BasicBlock::EndType::JUMPI:
		case BasicBlock::EndType::HANDOVER:
			assertThrow(
				blockByBeginPos.count(block.end),
				OptimizerException,
				"Successor block not found."
			);
			block.next = blockByBeginPos.at(block.end);
			break;
		default:
			break;
		}
	}
}

void ControlFlowGraph::removeUnusedBlocks()
{
	vector<BlockId> blocksToProcess{BlockId::initial()};
	set<BlockId> neededBlocks{BlockId::initial()};
	while (!blocksToProcess.empty())
	{
		BasicBlock const& block = m_blocks.at(blocksToProcess.back());
		blocksToProcess.pop_back();
		for (BlockId tag: block.pushedTags)
			if (!neededBlocks.count(tag) && m_blocks.count(tag))
			{
				neededBlocks.insert(tag);
				blocksToProcess.push_back(tag);
			}
		if (block.next && !neededBlocks.count(block.next))
		{
			neededBlocks.insert(block.next);
			blocksToProcess.push_back(block.next);
		}
	}
	for (auto it = m_blocks.begin(); it != m_blocks.end();)
		if (neededBlocks.count(it->first))
			++it;
		else
			m_blocks.erase(it++);
}

void ControlFlowGraph::setPrevLinks()
{
	for (auto& idAndBlock: m_blocks)
	{
		BasicBlock& block = idAndBlock.second;
		switch (block.endType)
		{
		case BasicBlock::EndType::JUMPI:
		case BasicBlock::EndType::HANDOVER:
			assertThrow(
				!m_blocks.at(block.next).prev,
				OptimizerException,
				"Successor already has predecessor."
			);
			m_blocks[block.next].prev = idAndBlock.first;
			break;
		default:
			break;
		}
	}
	// If block ends with jump to not yet linked block, link them removing the jump
	for (auto& idAndBlock: m_blocks)
	{
		BlockId blockId = idAndBlock.first;
		BasicBlock& block = idAndBlock.second;
		if (block.endType != BasicBlock::EndType::JUMP || block.end - block.begin < 2)
			continue;
		AssemblyItem const& push = m_items.at(block.end - 2);
		if (push.type() != PushTag)
			continue;
		BlockId nextId(push.data());
		if (m_blocks.count(nextId) && m_blocks.at(nextId).prev)
			continue;
		bool hasLoop = false;
		for (BlockId id = nextId; id && m_blocks.count(id) && !hasLoop; id = m_blocks.at(id).next)
			hasLoop = (id == blockId);
		if (hasLoop || !m_blocks.count(nextId))
			continue;

		m_blocks[nextId].prev = blockId;
		block.next = nextId;
		block.end -= 2;
		assertThrow(
			!block.pushedTags.empty() && block.pushedTags.back() == nextId,
			OptimizerException,
			"Last pushed tag not at end of pushed list."
		);
		block.pushedTags.pop_back();
		block.endType = BasicBlock::EndType::HANDOVER;
	}
}

void ControlFlowGraph::gatherKnowledge()
{
	// @todo actually we know that memory is filled with zeros at the beginning,
	// we could make use of that.
	KnownStatePointer emptyState = make_shared<KnownState>();
	bool unknownJumpEncountered = false;

	struct WorkQueueItem {
		BlockId blockId;
		KnownStatePointer state;
		set<BlockId> blocksSeen;
	};

	vector<WorkQueueItem> workQueue{WorkQueueItem{BlockId::initial(), emptyState->copy(), set<BlockId>()}};
	auto addWorkQueueItem = [&](WorkQueueItem const& _currentItem, BlockId _to, KnownStatePointer const& _state)
	{
		WorkQueueItem item;
		item.blockId = _to;
		item.state = _state->copy();
		item.blocksSeen = _currentItem.blocksSeen;
		item.blocksSeen.insert(_currentItem.blockId);
		workQueue.push_back(move(item));
	};

	while (!workQueue.empty())
	{
		WorkQueueItem item = move(workQueue.back());
		workQueue.pop_back();
		//@todo we might have to do something like incrementing the sequence number for each JUMPDEST
		assertThrow(!!item.blockId, OptimizerException, "");
		if (!m_blocks.count(item.blockId))
			continue; // too bad, we do not know the tag, probably an invalid jump
		BasicBlock& block = m_blocks.at(item.blockId);
		KnownStatePointer state = item.state;
		if (block.startState)
		{
			state->reduceToCommonKnowledge(*block.startState, !item.blocksSeen.count(item.blockId));
			if (*state == *block.startState)
				continue;
		}

		block.startState = state->copy();

		// Feed all items except for the final jump yet because it will erase the target tag.
		unsigned pc = block.begin;
		while (pc < block.end && !SemanticInformation::altersControlFlow(m_items.at(pc)))
			state->feedItem(m_items.at(pc++));

		if (
			block.endType == BasicBlock::EndType::JUMP ||
			block.endType == BasicBlock::EndType::JUMPI
		)
		{
			assertThrow(block.begin <= pc && pc == block.end - 1, OptimizerException, "");
			//@todo in the case of JUMPI, add knowledge about the condition to the state
			// (for both values of the condition)
			set<u256> tags = state->tagsInExpression(
				state->stackElement(state->stackHeight(), SourceLocation())
			);
			state->feedItem(m_items.at(pc++));

			if (tags.empty())
			{
				if (!unknownJumpEncountered)
				{
					// We do not know the target of this jump, so we have to reset the states of all
					// JUMPDESTs.
					unknownJumpEncountered = true;
					for (auto const& it: m_blocks)
						if (it.second.begin < it.second.end && m_items[it.second.begin].type() == Tag)
							workQueue.push_back(WorkQueueItem{it.first, emptyState, set<BlockId>()});
				}
			}
			else
				for (auto tag: tags)
					addWorkQueueItem(item, BlockId(tag), state);
		}
		else if (block.begin <= pc && pc < block.end)
			state->feedItem(m_items.at(pc++));
		assertThrow(block.end <= block.begin || pc == block.end, OptimizerException, "");

		block.endState = state;

		if (
			block.endType == BasicBlock::EndType::HANDOVER ||
			block.endType == BasicBlock::EndType::JUMPI
		)
			addWorkQueueItem(item, block.next, state);
	}

	// Remove all blocks we never visited here. This might happen because a tag is pushed but
	// never used for a JUMP.
	// Note that this invalidates some contents of pushedTags
	for (auto it = m_blocks.begin(); it != m_blocks.end();)
		if (!it->second.startState)
			it = m_blocks.erase(it);
		else
			it++;
}

BasicBlocks ControlFlowGraph::rebuildCode()
{
	map<BlockId, unsigned> pushes;
	for (auto& idAndBlock: m_blocks)
		for (BlockId ref: idAndBlock.second.pushedTags)
			if (m_blocks.count(ref))
				pushes[ref]++;

	set<BlockId> blocksToAdd;
	for (auto it: m_blocks)
		blocksToAdd.insert(it.first);
	set<BlockId> blocksAdded;
	BasicBlocks blocks;

	for (
		BlockId blockId = BlockId::initial();
		blockId;
		blockId = blocksToAdd.empty() ? BlockId::invalid() : *blocksToAdd.begin()
	)
	{
		bool previousHandedOver = (blockId == BlockId::initial());
		while (m_blocks.at(blockId).prev)
			blockId = m_blocks.at(blockId).prev;
		for (; blockId; blockId = m_blocks.at(blockId).next)
		{
			BasicBlock& block = m_blocks.at(blockId);
			blocksToAdd.erase(blockId);
			blocksAdded.insert(blockId);

			if (block.begin == block.end)
				continue;
			// If block starts with unused tag, skip it.
			if (previousHandedOver && !pushes[blockId] && m_items[block.begin].type() == Tag)
				++block.begin;
			if (block.begin < block.end)
			{
				blocks.push_back(block);
				blocks.back().startState->clearTagUnions();
				blocks.back().endState->clearTagUnions();
			}
			previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
		}
	}

	return blocks;
}

BlockId ControlFlowGraph::generateNewId()
{
	BlockId id = BlockId(++m_lastUsedId);
	assertThrow(id < BlockId::initial(), OptimizerException, "Out of block IDs.");
	return id;
}
<commit_msg>Fix: Copy empty state.<commit_after>/*
	This file is part of cpp-ethereum.

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

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @file ControlFlowGraph.cpp
 * @author Christian <c@ethdev.com>
 * @date 2015
 * Control flow analysis for the optimizer.
 */

#include <libevmasm/ControlFlowGraph.h>
#include <map>
#include <memory>
#include <algorithm>
#include <libevmasm/Exceptions.h>
#include <libevmasm/AssemblyItem.h>
#include <libevmasm/SemanticInformation.h>
#include <libevmasm/KnownState.h>

using namespace std;
using namespace dev;
using namespace dev::eth;

BlockId::BlockId(u256 const& _id):
	m_id(unsigned(_id))
{
	assertThrow( _id < initial().m_id, OptimizerException, "Tag number too large.");
}

BasicBlocks ControlFlowGraph::optimisedBlocks()
{
	if (m_items.empty())
		return BasicBlocks();

	findLargestTag();
	splitBlocks();
	resolveNextLinks();
	removeUnusedBlocks();
	setPrevLinks();
	gatherKnowledge();

	return rebuildCode();
}

void ControlFlowGraph::findLargestTag()
{
	m_lastUsedId = 0;
	for (auto const& item: m_items)
		if (item.type() == Tag || item.type() == PushTag)
		{
			// Assert that it can be converted.
			BlockId(item.data());
			m_lastUsedId = max(unsigned(item.data()), m_lastUsedId);
		}
}

void ControlFlowGraph::splitBlocks()
{
	m_blocks.clear();
	BlockId id = BlockId::initial();
	m_blocks[id].begin = 0;
	for (size_t index = 0; index < m_items.size(); ++index)
	{
		AssemblyItem const& item = m_items.at(index);
		if (item.type() == Tag)
		{
			if (id)
				m_blocks[id].end = index;
			id = BlockId::invalid();
		}
		if (!id)
		{
			id = item.type() == Tag ? BlockId(item.data()) : generateNewId();
			m_blocks[id].begin = index;
		}
		if (item.type() == PushTag)
			m_blocks[id].pushedTags.push_back(BlockId(item.data()));
		if (SemanticInformation::altersControlFlow(item))
		{
			m_blocks[id].end = index + 1;
			if (item == Instruction::JUMP)
				m_blocks[id].endType = BasicBlock::EndType::JUMP;
			else if (item == Instruction::JUMPI)
				m_blocks[id].endType = BasicBlock::EndType::JUMPI;
			else
				m_blocks[id].endType = BasicBlock::EndType::STOP;
			id = BlockId::invalid();
		}
	}
	if (id)
	{
		m_blocks[id].end = m_items.size();
		if (m_blocks[id].endType == BasicBlock::EndType::HANDOVER)
			m_blocks[id].endType = BasicBlock::EndType::STOP;
	}
}

void ControlFlowGraph::resolveNextLinks()
{
	map<unsigned, BlockId> blockByBeginPos;
	for (auto const& idAndBlock: m_blocks)
		if (idAndBlock.second.begin != idAndBlock.second.end)
			blockByBeginPos[idAndBlock.second.begin] = idAndBlock.first;

	for (auto& idAndBlock: m_blocks)
	{
		BasicBlock& block = idAndBlock.second;
		switch (block.endType)
		{
		case BasicBlock::EndType::JUMPI:
		case BasicBlock::EndType::HANDOVER:
			assertThrow(
				blockByBeginPos.count(block.end),
				OptimizerException,
				"Successor block not found."
			);
			block.next = blockByBeginPos.at(block.end);
			break;
		default:
			break;
		}
	}
}

void ControlFlowGraph::removeUnusedBlocks()
{
	vector<BlockId> blocksToProcess{BlockId::initial()};
	set<BlockId> neededBlocks{BlockId::initial()};
	while (!blocksToProcess.empty())
	{
		BasicBlock const& block = m_blocks.at(blocksToProcess.back());
		blocksToProcess.pop_back();
		for (BlockId tag: block.pushedTags)
			if (!neededBlocks.count(tag) && m_blocks.count(tag))
			{
				neededBlocks.insert(tag);
				blocksToProcess.push_back(tag);
			}
		if (block.next && !neededBlocks.count(block.next))
		{
			neededBlocks.insert(block.next);
			blocksToProcess.push_back(block.next);
		}
	}
	for (auto it = m_blocks.begin(); it != m_blocks.end();)
		if (neededBlocks.count(it->first))
			++it;
		else
			m_blocks.erase(it++);
}

void ControlFlowGraph::setPrevLinks()
{
	for (auto& idAndBlock: m_blocks)
	{
		BasicBlock& block = idAndBlock.second;
		switch (block.endType)
		{
		case BasicBlock::EndType::JUMPI:
		case BasicBlock::EndType::HANDOVER:
			assertThrow(
				!m_blocks.at(block.next).prev,
				OptimizerException,
				"Successor already has predecessor."
			);
			m_blocks[block.next].prev = idAndBlock.first;
			break;
		default:
			break;
		}
	}
	// If block ends with jump to not yet linked block, link them removing the jump
	for (auto& idAndBlock: m_blocks)
	{
		BlockId blockId = idAndBlock.first;
		BasicBlock& block = idAndBlock.second;
		if (block.endType != BasicBlock::EndType::JUMP || block.end - block.begin < 2)
			continue;
		AssemblyItem const& push = m_items.at(block.end - 2);
		if (push.type() != PushTag)
			continue;
		BlockId nextId(push.data());
		if (m_blocks.count(nextId) && m_blocks.at(nextId).prev)
			continue;
		bool hasLoop = false;
		for (BlockId id = nextId; id && m_blocks.count(id) && !hasLoop; id = m_blocks.at(id).next)
			hasLoop = (id == blockId);
		if (hasLoop || !m_blocks.count(nextId))
			continue;

		m_blocks[nextId].prev = blockId;
		block.next = nextId;
		block.end -= 2;
		assertThrow(
			!block.pushedTags.empty() && block.pushedTags.back() == nextId,
			OptimizerException,
			"Last pushed tag not at end of pushed list."
		);
		block.pushedTags.pop_back();
		block.endType = BasicBlock::EndType::HANDOVER;
	}
}

void ControlFlowGraph::gatherKnowledge()
{
	// @todo actually we know that memory is filled with zeros at the beginning,
	// we could make use of that.
	KnownStatePointer emptyState = make_shared<KnownState>();
	bool unknownJumpEncountered = false;

	struct WorkQueueItem {
		BlockId blockId;
		KnownStatePointer state;
		set<BlockId> blocksSeen;
	};

	vector<WorkQueueItem> workQueue{WorkQueueItem{BlockId::initial(), emptyState->copy(), set<BlockId>()}};
	auto addWorkQueueItem = [&](WorkQueueItem const& _currentItem, BlockId _to, KnownStatePointer const& _state)
	{
		WorkQueueItem item;
		item.blockId = _to;
		item.state = _state->copy();
		item.blocksSeen = _currentItem.blocksSeen;
		item.blocksSeen.insert(_currentItem.blockId);
		workQueue.push_back(move(item));
	};

	while (!workQueue.empty())
	{
		WorkQueueItem item = move(workQueue.back());
		workQueue.pop_back();
		//@todo we might have to do something like incrementing the sequence number for each JUMPDEST
		assertThrow(!!item.blockId, OptimizerException, "");
		if (!m_blocks.count(item.blockId))
			continue; // too bad, we do not know the tag, probably an invalid jump
		BasicBlock& block = m_blocks.at(item.blockId);
		KnownStatePointer state = item.state;
		if (block.startState)
		{
			state->reduceToCommonKnowledge(*block.startState, !item.blocksSeen.count(item.blockId));
			if (*state == *block.startState)
				continue;
		}

		block.startState = state->copy();

		// Feed all items except for the final jump yet because it will erase the target tag.
		unsigned pc = block.begin;
		while (pc < block.end && !SemanticInformation::altersControlFlow(m_items.at(pc)))
			state->feedItem(m_items.at(pc++));

		if (
			block.endType == BasicBlock::EndType::JUMP ||
			block.endType == BasicBlock::EndType::JUMPI
		)
		{
			assertThrow(block.begin <= pc && pc == block.end - 1, OptimizerException, "");
			//@todo in the case of JUMPI, add knowledge about the condition to the state
			// (for both values of the condition)
			set<u256> tags = state->tagsInExpression(
				state->stackElement(state->stackHeight(), SourceLocation())
			);
			state->feedItem(m_items.at(pc++));

			if (tags.empty())
			{
				if (!unknownJumpEncountered)
				{
					// We do not know the target of this jump, so we have to reset the states of all
					// JUMPDESTs.
					unknownJumpEncountered = true;
					for (auto const& it: m_blocks)
						if (it.second.begin < it.second.end && m_items[it.second.begin].type() == Tag)
							workQueue.push_back(WorkQueueItem{it.first, emptyState->copy(), set<BlockId>()});
				}
			}
			else
				for (auto tag: tags)
					addWorkQueueItem(item, BlockId(tag), state);
		}
		else if (block.begin <= pc && pc < block.end)
			state->feedItem(m_items.at(pc++));
		assertThrow(block.end <= block.begin || pc == block.end, OptimizerException, "");

		block.endState = state;

		if (
			block.endType == BasicBlock::EndType::HANDOVER ||
			block.endType == BasicBlock::EndType::JUMPI
		)
			addWorkQueueItem(item, block.next, state);
	}

	// Remove all blocks we never visited here. This might happen because a tag is pushed but
	// never used for a JUMP.
	// Note that this invalidates some contents of pushedTags
	for (auto it = m_blocks.begin(); it != m_blocks.end();)
		if (!it->second.startState)
			it = m_blocks.erase(it);
		else
			it++;
}

BasicBlocks ControlFlowGraph::rebuildCode()
{
	map<BlockId, unsigned> pushes;
	for (auto& idAndBlock: m_blocks)
		for (BlockId ref: idAndBlock.second.pushedTags)
			if (m_blocks.count(ref))
				pushes[ref]++;

	set<BlockId> blocksToAdd;
	for (auto it: m_blocks)
		blocksToAdd.insert(it.first);
	set<BlockId> blocksAdded;
	BasicBlocks blocks;

	for (
		BlockId blockId = BlockId::initial();
		blockId;
		blockId = blocksToAdd.empty() ? BlockId::invalid() : *blocksToAdd.begin()
	)
	{
		bool previousHandedOver = (blockId == BlockId::initial());
		while (m_blocks.at(blockId).prev)
			blockId = m_blocks.at(blockId).prev;
		for (; blockId; blockId = m_blocks.at(blockId).next)
		{
			BasicBlock& block = m_blocks.at(blockId);
			blocksToAdd.erase(blockId);
			blocksAdded.insert(blockId);

			if (block.begin == block.end)
				continue;
			// If block starts with unused tag, skip it.
			if (previousHandedOver && !pushes[blockId] && m_items[block.begin].type() == Tag)
				++block.begin;
			if (block.begin < block.end)
			{
				blocks.push_back(block);
				blocks.back().startState->clearTagUnions();
				blocks.back().endState->clearTagUnions();
			}
			previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
		}
	}

	return blocks;
}

BlockId ControlFlowGraph::generateNewId()
{
	BlockId id = BlockId(++m_lastUsedId);
	assertThrow(id < BlockId::initial(), OptimizerException, "Out of block IDs.");
	return id;
}
<|endoftext|>


<commit_before>
#include "CPExceptions.h"
#include "CPState.h"

static long iT = get_param_index("T");
static long iP = get_param_index("P");
static long iQ = get_param_index("Q");
static long iH = get_param_index("H");
static long iS = get_param_index("S");
static long iD = get_param_index("D");

// Constructor with fluid name
CoolPropStateClass::CoolPropStateClass(std::string Fluid){
	// Set the fluid name string
	_Fluid = Fluid;
	// Try to get the index of the fluid
	long iFluid = get_Fluid_index(_Fluid);
	// If iFluid is greater than 0, it is a CoolProp Fluid, otherwise not
	if (iFluid > 0)
	{
		// Get a pointer to the fluid object
		pFluid = get_fluid(iFluid);
	}
	else
	{
		throw ValueError("Bad Fluid name - not a CoolProp fluid");
	}
}

// Constructor with pointer to fluid
CoolPropStateClass::CoolPropStateClass(Fluid * pFluid){
	this->pFluid = pFluid;
}

bool match_pair(long iI1, long iI2, long I1, long I2)
{
	return ((iI1 == I1 || iI1 == I2) && (iI2 == I1 || iI2 == I2) && iI1!=iI2);
}
void sort_pair(long *iInput1, double *Value1, long *iInput2, double *Value2, long I1, long I2)
{
	if (!(*iInput1 == I1) || !(*iInput2 == I2)){
		std::swap(iInput1,iInput2);
		std::swap(Value1,Value2);
	}
}
void CoolPropStateClass::check_saturated_quality(double Q){
	double mach_eps = 1e-14;

	if (fabs(Q-1) < mach_eps){
		SaturatedL = true; SaturatedV = false;
	}
	else if (fabs(Q) < mach_eps){
		SaturatedL = false; SaturatedV = true;
	}
	else{
		SaturatedL = false; SaturatedV = false;
	}
}
// Main updater function
void CoolPropStateClass::update(long iInput1, double Value1, long iInput2, double Value2){
	/* Options for inputs (in either order) are:
	|  T,P
	|  T,D
	|  H,P
	|  S,P
	|  P,Q
	|  T,Q
	|
	*/
	// If flag_SinglePhase is true, it will always assume that it is not in the two-phase region
	// Can be over-written by changing the flag to true
	flag_SinglePhase = false;

	// Don't know if it is single phase or not, so assume it isn't
	SinglePhase = false;

	// If the inputs are P,Q or T,Q , it is guaranteed to require a call to the saturation routine
	if (match_pair(iInput1,iInput2,iP,iQ) || match_pair(iInput1,iInput2,iT,iQ)){
		update_twophase(iInput1,Value1,iInput2,Value2);
	}
	else if (match_pair(iInput1,iInput2,iT,iD)){
		update_Trho(iInput1,Value1,iInput2,Value2);
	}
	else if (match_pair(iInput1,iInput2,iT,iP)){
		update_Tp(iInput1,Value1,iInput2,Value2);
	}
	else if (match_pair(iInput1,iInput2,iP,iH)){
		update_ph(iInput1,Value1,iInput2,Value2);
	}
	else
	{
		throw ValueError(format("Sorry your inputs didn't work"));
	}
	/*		 match_pair(iInput1,iInput2,iS,iP)){
		 // Now you need to first figure out what the phase is, and then based on that work out the rest of the parameters

	}*/
}
void CoolPropStateClass::update_twophase(long iInput1, double Value1, long iInput2, double Value2)
{
	// This function handles setting internal variables when the state is known to be saturated
	// Either T,Q or P,Q are given
	double Q;

	SinglePhase = false;
	TwoPhase = true;

	if (iInput1 == iQ){
		Q = Value1;
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iInput2,iQ);
	}
	else{
		Q = Value2;
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iInput1,iQ);
	}

	// Check whether saturated liquid or vapor
	check_saturated_quality(Q);

	if (match_pair(iInput1,iInput2,iP,iQ)){
		// Sort so they are in the order P, Q
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iP,iQ);
		// Carry out the saturation call to get the temperature and density for each phases
		if (pFluid->pure()){
			pFluid->TsatP_Pure(Value1, &TsatL, &rhosatL, &rhosatV);
			TsatV = TsatL;
		}
		else{
			TsatL = pFluid->Tsat_anc(Value1,0);
			TsatV = pFluid->Tsat_anc(Value1,1);
			psatL = Value1;
			psatV = Value1;
			// Saturation densities
			rhosatL = pFluid->density_Tp(TsatL, psatL, pFluid->rhosatL(TsatL));
			rhosatV = pFluid->density_Tp(TsatV, psatV, pFluid->rhosatV(TsatV));
		}
	}
	else{
		// Sort so they are in the order T, Q
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iT,iQ);
		// Carry out the saturation call to get the temperature and density for each phases
		if (pFluid->pure()){
			pFluid->saturation(Value1,false,&psatL,&psatV,&rhosatL,&rhosatV);
			TsatL = Value1;
			TsatV = Value1;
		}
		else{
			TsatL = Value1;
			TsatV = Value1;
			// Saturation pressures
			psatL = pFluid->psatL_anc(TsatL);
			psatV = pFluid->psatV_anc(TsatV);
			// Saturation densities
			rhosatL = pFluid->density_Tp(TsatL, psatL, pFluid->rhosatL(TsatL));
			rhosatV = pFluid->density_Tp(TsatV, psatV, pFluid->rhosatV(TsatV));
		}
	}
	// Set internal variables
	_T = Q*TsatV+(1-Q)*TsatL;
	_rho = 1/(Q/rhosatV+(1-Q)/rhosatL);
	_p = Q*psatV+(1-Q)*psatL;
	_Q = Q;
}

// Updater if T,rho are inputs
void CoolPropStateClass::update_Trho(long iInput1, double Value1, long iInput2, double Value2)
{
	// Get them in the right order
	sort_pair(&iInput1,&Value1,&iInput2,&Value2,iT,iD);

	// Set internal variables
	_T = Value1;
	_rho = Value2;

	// If either SinglePhase or flag_SinglePhase is set to true, it will not make the call to the saturation routine
	// SinglePhase is set by the class routines, and flag_SinglePhase is a flag that can be set externally
	if (!SinglePhase || !flag_SinglePhase || !pFluid->phase_Trho(_T,_rho,&psatL,&psatV,&rhosatL,&rhosatV).compare("Two-Phase"))
	{
		// If it made it to the saturation routine and it is two-phase the saturation variables have been set
		TwoPhase = true;
		SinglePhase = false;

		// Get the quality and pressure
		_Q = (1/_rho-1/rhosatL)/(1/rhosatV-1/rhosatL);
		_p = _Q*psatV+(1-_Q)*psatL;

		check_saturated_quality(_Q);
	}
	else{
		TwoPhase = false;
		SinglePhase = true;
		SaturatedL = false;
		SaturatedV = false;
		_p = pFluid->pressure_Trho(_T,_rho);
	}
}

// Updater if T,p are inputs
void CoolPropStateClass::update_Tp(long iInput1, double Value1, long iInput2, double Value2)
{
	// Get them in the right order
	sort_pair(&iInput1,&Value1,&iInput2,&Value2,iT,iP);

	// Set internal variables
	_T = Value1;
	_p = Value2;

	// If either SinglePhase or flag_SinglePhase is set to true, it will not make the call to the saturation routine
	// SinglePhase is set by the class routines, and flag_SinglePhase is a flag that can be set externally
	if (!SinglePhase && !flag_SinglePhase && !pFluid->phase_Tp(_T,_p,&psatL,&psatV,&rhosatL,&rhosatV).compare("Two-Phase"))
	{
		// If it made it to the saturation routine and it is two-phase the saturation variables have been set
		TwoPhase = true;
		SinglePhase = false;

		// Get the quality and pressure
		_Q = (1/_rho-1/rhosatL)/(1/rhosatV-1/rhosatL);
		_p = _Q*psatV+(1-_Q)*psatL;

		check_saturated_quality(_Q);
		if (pFluid->pure()){
			TsatL = _T;
			TsatV = _T;
		}
		else{
			TsatL = _T;
			TsatV = _T;
		}
	}
	else{
		TwoPhase = false;
		SinglePhase = true;
		SaturatedL = false;
		SaturatedV = false;
		_rho = pFluid->density_Tp(_T,_p);
	}
}

// Updater if p,h are inputs
void CoolPropStateClass::update_ph(long iInput1, double Value1, long iInput2, double Value2)
{
	// Get them in the right order
	sort_pair(&iInput1,&Value1,&iInput2,&Value2,iP,iH);

	// Solve for temperature and pressure
	pFluid->Temperature_ph(Value1, Value2,&_T,&_rho,&rhosatL,&rhosatV,&TsatL,&TsatV);

	// Set internal variables
	_p = Value1;

	// Set the phase flags
	if ( _T < pFluid->reduce.T && _rho < rhosatL && _rho > rhosatV)
	{
		TwoPhase = true;
		SinglePhase = false;
		_Q = (1/_rho-1/rhosatL)/(1/rhosatV-1/rhosatL);
		check_saturated_quality(_Q);

		psatL = _p;
		psatV = _p;
	}
	else
	{
		TwoPhase = false;
		SinglePhase = true;
		SaturatedL = false;
		SaturatedV = true;
	}
}

double CoolPropStateClass::h(void){
	if (TwoPhase){
		return _Q*hV()+(1-_Q)*hL();
	}
	else{
		return pFluid->enthalpy_Trho(_T,_rho);
	}
}
double CoolPropStateClass::s(void){
	if (TwoPhase){
		return _Q*sV()+(1-_Q)*sL();
	}
	else{
		return pFluid->entropy_Trho(_T,_rho);
	}
}
double CoolPropStateClass::cp(void){
	return pFluid->specific_heat_p_Trho(_T,_rho);
}
double CoolPropStateClass::cv(void){
	return pFluid->specific_heat_v_Trho(_T,_rho);
}
double CoolPropStateClass::speed_sound(void){
	return pFluid->speed_sound_Trho(_T,_rho);
}
double CoolPropStateClass::drhodT_constp(void){
	return DerivTerms("drhodT|p",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
double CoolPropStateClass::drhodh_constp(void){
	return DerivTerms("drhodh|p",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
double CoolPropStateClass::drhodp_consth(void){
	return DerivTerms("drhodp|h",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
double CoolPropStateClass::dpdrho_constT(void){
	return DerivTerms("dpdrho|T",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
<commit_msg>Fixed CPState.cpp: swap needs values not pointers<commit_after>
#include "CPExceptions.h"
#include "CPState.h"

static long iT = get_param_index("T");
static long iP = get_param_index("P");
static long iQ = get_param_index("Q");
static long iH = get_param_index("H");
static long iS = get_param_index("S");
static long iD = get_param_index("D");

// Constructor with fluid name
CoolPropStateClass::CoolPropStateClass(std::string Fluid){
	// Set the fluid name string
	_Fluid = Fluid;
	// Try to get the index of the fluid
	long iFluid = get_Fluid_index(_Fluid);
	// If iFluid is greater than 0, it is a CoolProp Fluid, otherwise not
	if (iFluid > 0)
	{
		// Get a pointer to the fluid object
		pFluid = get_fluid(iFluid);
	}
	else
	{
		throw ValueError("Bad Fluid name - not a CoolProp fluid");
	}
}

// Constructor with pointer to fluid
CoolPropStateClass::CoolPropStateClass(Fluid * pFluid){
	this->pFluid = pFluid;
}

bool match_pair(long iI1, long iI2, long I1, long I2)
{
	return ((iI1 == I1 || iI1 == I2) && (iI2 == I1 || iI2 == I2) && iI1!=iI2);
}
void sort_pair(long *iInput1, double *Value1, long *iInput2, double *Value2, long I1, long I2)
{
	if (!(*iInput1 == I1) || !(*iInput2 == I2)){
		std::swap(*iInput1,*iInput2);
		std::swap(*Value1,*Value2);
	}
}
void CoolPropStateClass::check_saturated_quality(double Q){
	double mach_eps = 1e-14;

	if (fabs(Q-1) < mach_eps){
		SaturatedL = true; SaturatedV = false;
	}
	else if (fabs(Q) < mach_eps){
		SaturatedL = false; SaturatedV = true;
	}
	else{
		SaturatedL = false; SaturatedV = false;
	}
}
// Main updater function
void CoolPropStateClass::update(long iInput1, double Value1, long iInput2, double Value2){
	/* Options for inputs (in either order) are:
	|  T,P
	|  T,D
	|  H,P
	|  S,P
	|  P,Q
	|  T,Q
	|
	*/
	// If flag_SinglePhase is true, it will always assume that it is not in the two-phase region
	// Can be over-written by changing the flag to true
	flag_SinglePhase = false;

	// Don't know if it is single phase or not, so assume it isn't
	SinglePhase = false;

	// If the inputs are P,Q or T,Q , it is guaranteed to require a call to the saturation routine
	if (match_pair(iInput1,iInput2,iP,iQ) || match_pair(iInput1,iInput2,iT,iQ)){
		update_twophase(iInput1,Value1,iInput2,Value2);
	}
	else if (match_pair(iInput1,iInput2,iT,iD)){
		update_Trho(iInput1,Value1,iInput2,Value2);
	}
	else if (match_pair(iInput1,iInput2,iT,iP)){
		update_Tp(iInput1,Value1,iInput2,Value2);
	}
	else if (match_pair(iInput1,iInput2,iP,iH)){
		update_ph(iInput1,Value1,iInput2,Value2);
	}
	else
	{
		throw ValueError(format("Sorry your inputs didn't work"));
	}
	/*		 match_pair(iInput1,iInput2,iS,iP)){
		 // Now you need to first figure out what the phase is, and then based on that work out the rest of the parameters

	}*/
}
void CoolPropStateClass::update_twophase(long iInput1, double Value1, long iInput2, double Value2)
{
	// This function handles setting internal variables when the state is known to be saturated
	// Either T,Q or P,Q are given
	double Q;

	SinglePhase = false;
	TwoPhase = true;

	if (iInput1 == iQ){
		Q = Value1;
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iInput2,iQ);
	}
	else{
		Q = Value2;
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iInput1,iQ);
	}

	// Check whether saturated liquid or vapor
	check_saturated_quality(Q);

	if (match_pair(iInput1,iInput2,iP,iQ)){
		// Sort so they are in the order P, Q
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iP,iQ);
		// Carry out the saturation call to get the temperature and density for each phases
		if (pFluid->pure()){
			pFluid->TsatP_Pure(Value1, &TsatL, &rhosatL, &rhosatV);
			TsatV = TsatL;
		}
		else{
			TsatL = pFluid->Tsat_anc(Value1,0);
			TsatV = pFluid->Tsat_anc(Value1,1);
			psatL = Value1;
			psatV = Value1;
			// Saturation densities
			rhosatL = pFluid->density_Tp(TsatL, psatL, pFluid->rhosatL(TsatL));
			rhosatV = pFluid->density_Tp(TsatV, psatV, pFluid->rhosatV(TsatV));
		}
	}
	else{
		// Sort so they are in the order T, Q
		sort_pair(&iInput1,&Value1,&iInput2,&Value2,iT,iQ);
		// Carry out the saturation call to get the temperature and density for each phases
		if (pFluid->pure()){
			pFluid->saturation(Value1,false,&psatL,&psatV,&rhosatL,&rhosatV);
			TsatL = Value1;
			TsatV = Value1;
		}
		else{
			TsatL = Value1;
			TsatV = Value1;
			// Saturation pressures
			psatL = pFluid->psatL_anc(TsatL);
			psatV = pFluid->psatV_anc(TsatV);
			// Saturation densities
			rhosatL = pFluid->density_Tp(TsatL, psatL, pFluid->rhosatL(TsatL));
			rhosatV = pFluid->density_Tp(TsatV, psatV, pFluid->rhosatV(TsatV));
		}
	}
	// Set internal variables
	_T = Q*TsatV+(1-Q)*TsatL;
	_rho = 1/(Q/rhosatV+(1-Q)/rhosatL);
	_p = Q*psatV+(1-Q)*psatL;
	_Q = Q;
}

// Updater if T,rho are inputs
void CoolPropStateClass::update_Trho(long iInput1, double Value1, long iInput2, double Value2)
{
	// Get them in the right order
	sort_pair(&iInput1,&Value1,&iInput2,&Value2,iT,iD);

	// Set internal variables
	_T = Value1;
	_rho = Value2;

	// If either SinglePhase or flag_SinglePhase is set to true, it will not make the call to the saturation routine
	// SinglePhase is set by the class routines, and flag_SinglePhase is a flag that can be set externally
	if (!SinglePhase || !flag_SinglePhase || !pFluid->phase_Trho(_T,_rho,&psatL,&psatV,&rhosatL,&rhosatV).compare("Two-Phase"))
	{
		// If it made it to the saturation routine and it is two-phase the saturation variables have been set
		TwoPhase = true;
		SinglePhase = false;

		// Get the quality and pressure
		_Q = (1/_rho-1/rhosatL)/(1/rhosatV-1/rhosatL);
		_p = _Q*psatV+(1-_Q)*psatL;

		check_saturated_quality(_Q);
	}
	else{
		TwoPhase = false;
		SinglePhase = true;
		SaturatedL = false;
		SaturatedV = false;
		_p = pFluid->pressure_Trho(_T,_rho);
	}
}

// Updater if T,p are inputs
void CoolPropStateClass::update_Tp(long iInput1, double Value1, long iInput2, double Value2)
{
	// Get them in the right order
	sort_pair(&iInput1,&Value1,&iInput2,&Value2,iT,iP);

	// Set internal variables
	_T = Value1;
	_p = Value2;

	// If either SinglePhase or flag_SinglePhase is set to true, it will not make the call to the saturation routine
	// SinglePhase is set by the class routines, and flag_SinglePhase is a flag that can be set externally
	if (!SinglePhase && !flag_SinglePhase && !pFluid->phase_Tp(_T,_p,&psatL,&psatV,&rhosatL,&rhosatV).compare("Two-Phase"))
	{
		// If it made it to the saturation routine and it is two-phase the saturation variables have been set
		TwoPhase = true;
		SinglePhase = false;

		// Get the quality and pressure
		_Q = (1/_rho-1/rhosatL)/(1/rhosatV-1/rhosatL);
		_p = _Q*psatV+(1-_Q)*psatL;

		check_saturated_quality(_Q);
		if (pFluid->pure()){
			TsatL = _T;
			TsatV = _T;
		}
		else{
			TsatL = _T;
			TsatV = _T;
		}
	}
	else{
		TwoPhase = false;
		SinglePhase = true;
		SaturatedL = false;
		SaturatedV = false;
		_rho = pFluid->density_Tp(_T,_p);
	}
}

// Updater if p,h are inputs
void CoolPropStateClass::update_ph(long iInput1, double Value1, long iInput2, double Value2)
{
	// Get them in the right order
	sort_pair(&iInput1,&Value1,&iInput2,&Value2,iP,iH);

	// Solve for temperature and pressure
	pFluid->Temperature_ph(Value1, Value2,&_T,&_rho,&rhosatL,&rhosatV,&TsatL,&TsatV);

	// Set internal variables
	_p = Value1;

	// Set the phase flags
	if ( _T < pFluid->reduce.T && _rho < rhosatL && _rho > rhosatV)
	{
		TwoPhase = true;
		SinglePhase = false;
		_Q = (1/_rho-1/rhosatL)/(1/rhosatV-1/rhosatL);
		check_saturated_quality(_Q);

		psatL = _p;
		psatV = _p;
	}
	else
	{
		TwoPhase = false;
		SinglePhase = true;
		SaturatedL = false;
		SaturatedV = true;
	}
}

double CoolPropStateClass::h(void){
	if (TwoPhase){
		return _Q*hV()+(1-_Q)*hL();
	}
	else{
		return pFluid->enthalpy_Trho(_T,_rho);
	}
}
double CoolPropStateClass::s(void){
	if (TwoPhase){
		return _Q*sV()+(1-_Q)*sL();
	}
	else{
		return pFluid->entropy_Trho(_T,_rho);
	}
}
double CoolPropStateClass::cp(void){
	return pFluid->specific_heat_p_Trho(_T,_rho);
}
double CoolPropStateClass::cv(void){
	return pFluid->specific_heat_v_Trho(_T,_rho);
}
double CoolPropStateClass::speed_sound(void){
	return pFluid->speed_sound_Trho(_T,_rho);
}
double CoolPropStateClass::drhodT_constp(void){
	return DerivTerms("drhodT|p",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
double CoolPropStateClass::drhodh_constp(void){
	return DerivTerms("drhodh|p",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
double CoolPropStateClass::drhodp_consth(void){
	return DerivTerms("drhodp|h",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
double CoolPropStateClass::dpdrho_constT(void){
	return DerivTerms("dpdrho|T",_T,_rho,pFluid,SinglePhase,TwoPhase);
}
<|endoftext|>


<commit_before>#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
// Needed on MsWindows
#include <windows.h>
#endif // Win32 platform

#include <GLUT/glut.h>
#include <vector>
#include "float2.h"
#include "Curve.h"
#include "Circle.h"
#include "Freedom.h"
#include "BezierCurve.h"
#include "LagrangeCurve.h"
#include "CurveInstance.h"

float TIME;

bool pol = false;
bool lan = false;
bool bez = false;

std::vector<Curve*> LC ;
std::vector<Curve*> BC ;
std::vector<CurveInstance*> CI;

std::vector<float> knots;

void onMouse(int button, int state, int x, int y) {
    int viewportRect[4];
    glGetIntegerv(GL_VIEWPORT, viewportRect);
    if (lan == true && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
        LC.at(0)->addControlPoint( float2(
                                              x * 2.0 / viewportRect[2] - 1.0,
                                              -y * 2.0 / viewportRect[3] + 1.0));
    if (bez == true && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
        BC.at(0)->addControlPoint( float2(
                                            x * 2.0 / viewportRect[2] - 1.0,
                                            -y * 2.0 / viewportRect[3] + 1.0));
    glutPostRedisplay();
}

void onKeyBoard(unsigned char key, int x, int y)
{

    if (key == 'p')
    {
        pol = true;
    } else {
        pol = false;

    }

    if (key == 'b')
    {
        bez = true;
    } else {
        bez = false;
    }

    if (key == 'l')
    {
        lan = true;
    } else {
        lan = false;
    }

    glutPostRedisplay();
}

void onIdle()
{
    TIME = glutGet(GLUT_ELAPSED_TIME) * .001 * 0.1 - floor(glutGet(GLUT_ELAPSED_TIME) * .001 *0.1) ;
    glutPostRedisplay();
}

void onDisplay( )
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3d(1,1,1);
    glLineWidth(4);
    glPointSize(8);

    LC.at(0)->drawControlPoints();
    LC.at(0)->draw();
    onIdle();
    LC.at(0)->drawTracker(TIME);

    BC.at(0)->drawControlPoints();
    BC.at(0)->draw();
    onIdle();
    BC.at(0)->drawTracker(TIME);

    onIdle();
    CI.at(0)->draw();

	glutSwapBuffers();

}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(
                        GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); //RGBA if you want an alpha channel for transparency
    glutCreateWindow("l02_Curves");

    BezierCurve *  b= new BezierCurve();
    LagrangeCurve * l = new LagrangeCurve();

    LC.push_back(l);
    BC.push_back(b);
    glutKeyboardFunc(onKeyBoard);
    glutMouseFunc(onMouse);

    CurveInstance * c = new CurveInstance(l, float2(0.5,0.5));
    CI.push_back(c);
    glutDisplayFunc(onDisplay);
    glutMainLoop();

    return 0;
}<commit_msg>changed name<commit_after>#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
// Needed on MsWindows
#include <windows.h>
#endif // Win32 platform

#include <GLUT/glut.h>
#include <vector>
#include "float2.h"
#include "Curve.h"
#include "Circle.h"
#include "Freedom.h"
#include "BezierCurve.h"
#include "LagrangeCurve.h"
#include "CurveInstance.h"

float TIME;

bool pol = false;
bool lag = false;
bool bez = false;

std::vector<Curve*> LC ;
std::vector<Curve*> BC ;
std::vector<CurveInstance*> CI;

std::vector<float> knots;

void onMouse(int button, int state, int x, int y) {
    int viewportRect[4];
    glGetIntegerv(GL_VIEWPORT, viewportRect);
    if (lag == true && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
        LC.at(0)->addControlPoint( float2(
                                              x * 2.0 / viewportRect[2] - 1.0,
                                              -y * 2.0 / viewportRect[3] + 1.0));
    if (bez == true && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
        BC.at(0)->addControlPoint( float2(
                                            x * 2.0 / viewportRect[2] - 1.0,
                                            -y * 2.0 / viewportRect[3] + 1.0));
    glutPostRedisplay();
}

void onKeyBoard(unsigned char key, int x, int y)
{

    if (key == 'p')
    {
        pol = true;
    } else {
        pol = false;

    }

    if (key == 'b')
    {
        bez = true;
    } else {
        bez = false;
    }

    if (key == 'l')
    {
        lag = true;
    } else {
        lag = false;
    }

    glutPostRedisplay();
}

void onIdle()
{
    TIME = glutGet(GLUT_ELAPSED_TIME) * .001 * 0.1 - floor(glutGet(GLUT_ELAPSED_TIME) * .001 *0.1) ;
    glutPostRedisplay();
}

void onDisplay( )
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor3d(1,1,1);
    glLineWidth(4);
    glPointSize(8);

    LC.at(0)->drawControlPoints();
    LC.at(0)->draw();
    onIdle();
    LC.at(0)->drawTracker(TIME);

    BC.at(0)->drawControlPoints();
    BC.at(0)->draw();
    onIdle();
    BC.at(0)->drawTracker(TIME);

    onIdle();
    CI.at(0)->draw();

	glutSwapBuffers();

}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(
                        GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); //RGBA if you want an alpha channel for transparency
    glutCreateWindow("l02_Curves");

    BezierCurve *  b= new BezierCurve();
    LagrangeCurve * l = new LagrangeCurve();

    LC.push_back(l);
    BC.push_back(b);
    glutKeyboardFunc(onKeyBoard);
    glutMouseFunc(onMouse);

    CurveInstance * c = new CurveInstance(l, float2(0.5,0.5));
    CI.push_back(c);
    glutDisplayFunc(onDisplay);
    glutMainLoop();

    return 0;
}<|endoftext|>