<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: brwview.cxx,v $
 *
 *  $Revision: 1.27 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-06 08:02:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"

#ifndef _SBA_BWRCTRLR_HXX
#include "brwctrlr.hxx"
#endif
#ifndef _SBX_BRWVIEW_HXX
#include "brwview.hxx"
#endif
#ifndef _SBA_GRID_HXX
#include "sbagrid.hxx"
#endif
#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/helper/vclunohelper.hxx>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _SV_SPLIT_HXX
#include <vcl/split.hxx>
#endif
#ifndef DBACCESS_UI_DBTREEVIEW_HXX
#include "dbtreeview.hxx"
#endif
#ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
#include "dbustrings.hrc"
#endif
#ifndef _DBU_BRW_HRC_
#include "dbu_brw.hrc"
#endif
#ifndef _COM_SUN_STAR_FORM_XLOADABLE_HPP_
#include <com/sun/star/form/XLoadable.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_XCONTROLCONTAINER_HPP_
#include <com/sun/star/awt/XControlContainer.hpp>
#endif
#ifndef DBAUI_TOOLS_HXX
#include "UITools.hxx"
#endif

using namespace dbaui;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::form;
//  using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;

namespace
{
    sal_Bool isGrabVclControlFocusAllowed(const UnoDataBrowserView* _pView)
    {
        sal_Bool bGrabFocus = sal_False;
        SbaGridControl* pVclControl = _pView->getVclControl();
        Reference< ::com::sun::star::awt::XControl > xGrid = _pView->getGridControl();
        if (pVclControl && xGrid.is())
        {
            bGrabFocus = sal_True;
            if(!pVclControl->HasChildPathFocus())
            {
                Reference<XChild> xChild(xGrid->getModel(),UNO_QUERY);
                Reference<XLoadable> xLoad;
                if(xChild.is())
                    xLoad.set(xChild->getParent(),UNO_QUERY);
                bGrabFocus = xLoad.is() && xLoad->isLoaded();
            }
        }
        return bGrabFocus;
    }
}
//==================================================================
//= UnoDataBrowserView
//==================================================================

DBG_NAME(UnoDataBrowserView)
// -------------------------------------------------------------------------
UnoDataBrowserView::UnoDataBrowserView( Window* pParent,
                                        IController* _pController,
                                        const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rFactory)
    :ODataView(pParent,_pController,_rFactory)
    ,m_pTreeView(NULL)
    ,m_pSplitter(NULL)
    ,m_pVclControl(NULL)
    ,m_pStatus(NULL)
{
    DBG_CTOR(UnoDataBrowserView,NULL);

}
// -------------------------------------------------------------------------
void UnoDataBrowserView::Construct(const Reference< ::com::sun::star::awt::XControlModel >& xModel)
{
    try
    {
        ODataView::Construct();

        // our UNO representation
        m_xMe = VCLUnoHelper::CreateControlContainer(this);

        // create the (UNO-) control
        m_xGrid = new SbaXGridControl(getORB());
        DBG_ASSERT(m_xGrid.is(), "UnoDataBrowserView::Construct : could not create a grid control !");
        // in design mode (for the moment)
        m_xGrid->setDesignMode(sal_True);

        Reference< ::com::sun::star::awt::XWindow >  xGridWindow(m_xGrid, UNO_QUERY);
        xGridWindow->setVisible(sal_True);
        xGridWindow->setEnable(sal_True);

        // introduce the model to the grid
        m_xGrid->setModel(xModel);
        // introduce the container (me) to the grid
        Reference< ::com::sun::star::beans::XPropertySet >  xModelSet(xModel, UNO_QUERY);
        getContainer()->addControl(::comphelper::getString(xModelSet->getPropertyValue(PROPERTY_NAME)), m_xGrid);

        // get the VCL-control
        m_pVclControl = NULL;
        getVclControl();

        DBG_ASSERT(m_pVclControl != NULL, "UnoDataBrowserView::Construct : no real grid control !");
    }
    catch(Exception&)
    {
        ::comphelper::disposeComponent(m_xGrid);
        throw;
    }
}
// -------------------------------------------------------------------------
UnoDataBrowserView::~UnoDataBrowserView()
{
    {
        ::std::auto_ptr<Splitter> aTemp(m_pSplitter);
        m_pSplitter = NULL;
    }
    setTreeView(NULL);

    if ( m_pStatus )
    {
        delete m_pStatus;
        m_pStatus = NULL;
    }

    try
    {
        ::comphelper::disposeComponent(m_xGrid);
        ::comphelper::disposeComponent(m_xMe);
    }
    catch(Exception)
    {}

    DBG_DTOR(UnoDataBrowserView,NULL);
}
// -----------------------------------------------------------------------------
IMPL_LINK( UnoDataBrowserView, SplitHdl, void*, /*NOINTERESTEDIN*/ )
{
    long nYPos = m_pSplitter->GetPosPixel().Y();
    m_pSplitter->SetPosPixel( Point( m_pSplitter->GetSplitPosPixel(), nYPos ) );
    Resize();

    return 0L;
}
// -------------------------------------------------------------------------
void UnoDataBrowserView::setSplitter(Splitter* _pSplitter)
{
    m_pSplitter = _pSplitter;
    m_pSplitter->SetSplitHdl( LINK( this, UnoDataBrowserView, SplitHdl ) );
    LINK( this, UnoDataBrowserView, SplitHdl ).Call(m_pSplitter);
}
// -------------------------------------------------------------------------
void UnoDataBrowserView::setTreeView(DBTreeView* _pTreeView)
{
    if (m_pTreeView != _pTreeView)
    {
        if (m_pTreeView)
        {
            ::std::auto_ptr<Window> aTemp(m_pTreeView);
            m_pTreeView = NULL;
        }
        m_pTreeView = _pTreeView;
    }
}
// -------------------------------------------------------------------------
void UnoDataBrowserView::showStatus( const String& _rStatus )
{
    if (0 == _rStatus.Len())
        hideStatus();
    else
    {
        if (!m_pStatus)
            m_pStatus = new FixedText(this);
        m_pStatus->SetText(_rStatus);
        m_pStatus->Show();
        Resize();
        Update();
    }
}

// -------------------------------------------------------------------------
void UnoDataBrowserView::hideStatus()
{
    if (!m_pStatus || !m_pStatus->IsVisible())
        // nothing to do
        return;
    m_pStatus->Hide();
    Resize();
    Update();
}

// -------------------------------------------------------------------------
void UnoDataBrowserView::resizeDocumentView(Rectangle& _rPlayground)
{
    Point   aSplitPos;
    Size    aSplitSize;
    Point   aPlaygroundPos( _rPlayground.TopLeft() );
    Size    aPlaygroundSize( _rPlayground.GetSize() );

    if (m_pTreeView && m_pTreeView->IsVisible() && m_pSplitter)
    {
        // calculate the splitter pos and size
        aSplitPos   = m_pSplitter->GetPosPixel();
        aSplitPos.Y() = aPlaygroundPos.Y();
        aSplitSize  = m_pSplitter->GetOutputSizePixel();
        aSplitSize.Height() = aPlaygroundSize.Height();

        if( ( aSplitPos.X() + aSplitSize.Width() ) > ( aPlaygroundSize.Width() ))
            aSplitPos.X() = aPlaygroundSize.Width() - aSplitSize.Width();

        if( aSplitPos.X() <= aPlaygroundPos.X() )
            aSplitPos.X() = aPlaygroundPos.X() + sal_Int32(aPlaygroundSize.Width() * 0.2);

        // the tree pos and size
        Point   aTreeViewPos( aPlaygroundPos );
        Size    aTreeViewSize( aSplitPos.X(), aPlaygroundSize.Height() );

        // the status pos and size
        if (m_pStatus && m_pStatus->IsVisible())
        {
            Size aStatusSize(aPlaygroundPos.X(), GetTextHeight() + 2);
            aStatusSize = LogicToPixel(aStatusSize, MAP_APPFONT);
            aStatusSize.Width() = aTreeViewSize.Width() - 2 - 2;

            Point aStatusPos( aPlaygroundPos.X() + 2, aTreeViewPos.Y() + aTreeViewSize.Height() - aStatusSize.Height() );
            m_pStatus->SetPosSizePixel( aStatusPos, aStatusSize );
            aTreeViewSize.Height() -= aStatusSize.Height();
        }

        // set the size of treelistbox
        m_pTreeView->SetPosSizePixel( aTreeViewPos, aTreeViewSize );

        //set the size of the splitter
        m_pSplitter->SetPosSizePixel( aSplitPos, Size( aSplitSize.Width(), aPlaygroundSize.Height() ) );
        m_pSplitter->SetDragRectPixel( _rPlayground );
    }

    // set the size of grid control
    Reference< ::com::sun::star::awt::XWindow >  xGridAsWindow(m_xGrid, UNO_QUERY);
    if (xGridAsWindow.is())
        xGridAsWindow->setPosSize( aSplitPos.X() + aSplitSize.Width(), aPlaygroundPos.Y(),
                                   aPlaygroundSize.Width() - aSplitSize.Width() - aSplitPos.X(), aPlaygroundSize.Height(), ::com::sun::star::awt::PosSize::POSSIZE);

    // just for completeness: there is no space left, we occupied it all ...
    _rPlayground.SetPos( _rPlayground.BottomRight() );
    _rPlayground.SetSize( Size( 0, 0 ) );
}

//------------------------------------------------------------------
sal_uInt16 UnoDataBrowserView::View2ModelPos(sal_uInt16 nPos) const
{
    return m_pVclControl ? m_pVclControl->GetModelColumnPos(m_pVclControl->GetColumnIdFromViewPos(nPos)) : -1;
}

// -----------------------------------------------------------------------------
SbaGridControl* UnoDataBrowserView::getVclControl() const
{
    if ( !m_pVclControl )
    {
        OSL_ENSURE(m_xGrid.is(),"Grid not set!");
        if ( m_xGrid.is() )
        {
            Reference< ::com::sun::star::awt::XWindowPeer >  xPeer = m_xGrid->getPeer();
            if ( xPeer.is() )
            {
                SbaXGridPeer* pPeer = SbaXGridPeer::getImplementation(xPeer);
                UnoDataBrowserView* pTHIS = const_cast<UnoDataBrowserView*>(this);
                if ( pPeer )
                {
                    m_pVclControl = static_cast<SbaGridControl*>(pPeer->GetWindow());
                    pTHIS->startComponentListening(Reference<XComponent>(VCLUnoHelper::GetInterface(m_pVclControl),UNO_QUERY));
                }
            }
        }
    }
    return m_pVclControl;
}
// -----------------------------------------------------------------------------
void UnoDataBrowserView::GetFocus()
{
    ODataView::GetFocus();
    if( m_pTreeView && m_pTreeView->IsVisible() && !m_pTreeView->HasChildPathFocus())
        m_pTreeView->GrabFocus();
    else if (m_pVclControl && m_xGrid.is())
    {
        sal_Bool bGrabFocus = sal_False;
        if(!m_pVclControl->HasChildPathFocus())
        {
            bGrabFocus = isGrabVclControlFocusAllowed(this);
            if( bGrabFocus )
                m_pVclControl->GrabFocus();
        }
        if(!bGrabFocus && m_pTreeView && m_pTreeView->IsVisible() )
            m_pTreeView->GrabFocus();
    }
}
// -----------------------------------------------------------------------------
void UnoDataBrowserView::_disposing( const ::com::sun::star::lang::EventObject& /*_rSource*/ )
{
    stopComponentListening(Reference<XComponent>(VCLUnoHelper::GetInterface(m_pVclControl),UNO_QUERY));
    m_pVclControl = NULL;
}
// -------------------------------------------------------------------------
long UnoDataBrowserView::PreNotify( NotifyEvent& rNEvt )
{
    long nDone = 0L;
    if(rNEvt.GetType() == EVENT_KEYINPUT)
    {
        sal_Bool bGrabAllowed = isGrabVclControlFocusAllowed(this);
        if ( bGrabAllowed )
        {
            const KeyEvent* pKeyEvt = rNEvt.GetKeyEvent();
            const KeyCode& rKeyCode = pKeyEvt->GetKeyCode();
            if (  ( rKeyCode == KeyCode( KEY_E, TRUE, TRUE, FALSE ) )
               || ( rKeyCode == KeyCode( KEY_TAB, TRUE, FALSE, FALSE ) )
               )
            {
                if ( m_pTreeView && m_pVclControl && m_pTreeView->HasChildPathFocus() )
                    m_pVclControl->GrabFocus();
                else if ( m_pTreeView && m_pVclControl && m_pVclControl->HasChildPathFocus() )
                    m_pTreeView->GrabFocus();

                nDone = 1L;
            }
        }
    }
    return nDone ? nDone : ODataView::PreNotify(rNEvt);
}

DBG_NAME(BrowserViewStatusDisplay)
// -----------------------------------------------------------------------------
BrowserViewStatusDisplay::BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const String& _rStatus )
    :m_pView(_pView)
{
    DBG_CTOR(BrowserViewStatusDisplay,NULL);

    if (m_pView)
        m_pView->showStatus(_rStatus);
}

// -----------------------------------------------------------------------------
BrowserViewStatusDisplay::~BrowserViewStatusDisplay( )
{
    if (m_pView)
        m_pView->showStatus(String());

    DBG_DTOR(BrowserViewStatusDisplay,NULL);
}
// -----------------------------------------------------------------------------
<commit_msg>INTEGRATION: CWS changefileheader (1.27.162); FILE MERGED 2008/03/31 13:27:07 rt 1.27.162.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: brwview.cxx,v $
 * $Revision: 1.28 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"

#ifndef _SBA_BWRCTRLR_HXX
#include "brwctrlr.hxx"
#endif
#ifndef _SBX_BRWVIEW_HXX
#include "brwview.hxx"
#endif
#ifndef _SBA_GRID_HXX
#include "sbagrid.hxx"
#endif
#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/helper/vclunohelper.hxx>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _SV_SPLIT_HXX
#include <vcl/split.hxx>
#endif
#ifndef DBACCESS_UI_DBTREEVIEW_HXX
#include "dbtreeview.hxx"
#endif
#ifndef DBACCESS_SHARED_DBUSTRINGS_HRC
#include "dbustrings.hrc"
#endif
#ifndef _DBU_BRW_HRC_
#include "dbu_brw.hrc"
#endif
#ifndef _COM_SUN_STAR_FORM_XLOADABLE_HPP_
#include <com/sun/star/form/XLoadable.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_XCONTROLCONTAINER_HPP_
#include <com/sun/star/awt/XControlContainer.hpp>
#endif
#ifndef DBAUI_TOOLS_HXX
#include "UITools.hxx"
#endif

using namespace dbaui;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::form;
//  using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;

namespace
{
    sal_Bool isGrabVclControlFocusAllowed(const UnoDataBrowserView* _pView)
    {
        sal_Bool bGrabFocus = sal_False;
        SbaGridControl* pVclControl = _pView->getVclControl();
        Reference< ::com::sun::star::awt::XControl > xGrid = _pView->getGridControl();
        if (pVclControl && xGrid.is())
        {
            bGrabFocus = sal_True;
            if(!pVclControl->HasChildPathFocus())
            {
                Reference<XChild> xChild(xGrid->getModel(),UNO_QUERY);
                Reference<XLoadable> xLoad;
                if(xChild.is())
                    xLoad.set(xChild->getParent(),UNO_QUERY);
                bGrabFocus = xLoad.is() && xLoad->isLoaded();
            }
        }
        return bGrabFocus;
    }
}
//==================================================================
//= UnoDataBrowserView
//==================================================================

DBG_NAME(UnoDataBrowserView)
// -------------------------------------------------------------------------
UnoDataBrowserView::UnoDataBrowserView( Window* pParent,
                                        IController* _pController,
                                        const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rFactory)
    :ODataView(pParent,_pController,_rFactory)
    ,m_pTreeView(NULL)
    ,m_pSplitter(NULL)
    ,m_pVclControl(NULL)
    ,m_pStatus(NULL)
{
    DBG_CTOR(UnoDataBrowserView,NULL);

}
// -------------------------------------------------------------------------
void UnoDataBrowserView::Construct(const Reference< ::com::sun::star::awt::XControlModel >& xModel)
{
    try
    {
        ODataView::Construct();

        // our UNO representation
        m_xMe = VCLUnoHelper::CreateControlContainer(this);

        // create the (UNO-) control
        m_xGrid = new SbaXGridControl(getORB());
        DBG_ASSERT(m_xGrid.is(), "UnoDataBrowserView::Construct : could not create a grid control !");
        // in design mode (for the moment)
        m_xGrid->setDesignMode(sal_True);

        Reference< ::com::sun::star::awt::XWindow >  xGridWindow(m_xGrid, UNO_QUERY);
        xGridWindow->setVisible(sal_True);
        xGridWindow->setEnable(sal_True);

        // introduce the model to the grid
        m_xGrid->setModel(xModel);
        // introduce the container (me) to the grid
        Reference< ::com::sun::star::beans::XPropertySet >  xModelSet(xModel, UNO_QUERY);
        getContainer()->addControl(::comphelper::getString(xModelSet->getPropertyValue(PROPERTY_NAME)), m_xGrid);

        // get the VCL-control
        m_pVclControl = NULL;
        getVclControl();

        DBG_ASSERT(m_pVclControl != NULL, "UnoDataBrowserView::Construct : no real grid control !");
    }
    catch(Exception&)
    {
        ::comphelper::disposeComponent(m_xGrid);
        throw;
    }
}
// -------------------------------------------------------------------------
UnoDataBrowserView::~UnoDataBrowserView()
{
    {
        ::std::auto_ptr<Splitter> aTemp(m_pSplitter);
        m_pSplitter = NULL;
    }
    setTreeView(NULL);

    if ( m_pStatus )
    {
        delete m_pStatus;
        m_pStatus = NULL;
    }

    try
    {
        ::comphelper::disposeComponent(m_xGrid);
        ::comphelper::disposeComponent(m_xMe);
    }
    catch(Exception)
    {}

    DBG_DTOR(UnoDataBrowserView,NULL);
}
// -----------------------------------------------------------------------------
IMPL_LINK( UnoDataBrowserView, SplitHdl, void*, /*NOINTERESTEDIN*/ )
{
    long nYPos = m_pSplitter->GetPosPixel().Y();
    m_pSplitter->SetPosPixel( Point( m_pSplitter->GetSplitPosPixel(), nYPos ) );
    Resize();

    return 0L;
}
// -------------------------------------------------------------------------
void UnoDataBrowserView::setSplitter(Splitter* _pSplitter)
{
    m_pSplitter = _pSplitter;
    m_pSplitter->SetSplitHdl( LINK( this, UnoDataBrowserView, SplitHdl ) );
    LINK( this, UnoDataBrowserView, SplitHdl ).Call(m_pSplitter);
}
// -------------------------------------------------------------------------
void UnoDataBrowserView::setTreeView(DBTreeView* _pTreeView)
{
    if (m_pTreeView != _pTreeView)
    {
        if (m_pTreeView)
        {
            ::std::auto_ptr<Window> aTemp(m_pTreeView);
            m_pTreeView = NULL;
        }
        m_pTreeView = _pTreeView;
    }
}
// -------------------------------------------------------------------------
void UnoDataBrowserView::showStatus( const String& _rStatus )
{
    if (0 == _rStatus.Len())
        hideStatus();
    else
    {
        if (!m_pStatus)
            m_pStatus = new FixedText(this);
        m_pStatus->SetText(_rStatus);
        m_pStatus->Show();
        Resize();
        Update();
    }
}

// -------------------------------------------------------------------------
void UnoDataBrowserView::hideStatus()
{
    if (!m_pStatus || !m_pStatus->IsVisible())
        // nothing to do
        return;
    m_pStatus->Hide();
    Resize();
    Update();
}

// -------------------------------------------------------------------------
void UnoDataBrowserView::resizeDocumentView(Rectangle& _rPlayground)
{
    Point   aSplitPos;
    Size    aSplitSize;
    Point   aPlaygroundPos( _rPlayground.TopLeft() );
    Size    aPlaygroundSize( _rPlayground.GetSize() );

    if (m_pTreeView && m_pTreeView->IsVisible() && m_pSplitter)
    {
        // calculate the splitter pos and size
        aSplitPos   = m_pSplitter->GetPosPixel();
        aSplitPos.Y() = aPlaygroundPos.Y();
        aSplitSize  = m_pSplitter->GetOutputSizePixel();
        aSplitSize.Height() = aPlaygroundSize.Height();

        if( ( aSplitPos.X() + aSplitSize.Width() ) > ( aPlaygroundSize.Width() ))
            aSplitPos.X() = aPlaygroundSize.Width() - aSplitSize.Width();

        if( aSplitPos.X() <= aPlaygroundPos.X() )
            aSplitPos.X() = aPlaygroundPos.X() + sal_Int32(aPlaygroundSize.Width() * 0.2);

        // the tree pos and size
        Point   aTreeViewPos( aPlaygroundPos );
        Size    aTreeViewSize( aSplitPos.X(), aPlaygroundSize.Height() );

        // the status pos and size
        if (m_pStatus && m_pStatus->IsVisible())
        {
            Size aStatusSize(aPlaygroundPos.X(), GetTextHeight() + 2);
            aStatusSize = LogicToPixel(aStatusSize, MAP_APPFONT);
            aStatusSize.Width() = aTreeViewSize.Width() - 2 - 2;

            Point aStatusPos( aPlaygroundPos.X() + 2, aTreeViewPos.Y() + aTreeViewSize.Height() - aStatusSize.Height() );
            m_pStatus->SetPosSizePixel( aStatusPos, aStatusSize );
            aTreeViewSize.Height() -= aStatusSize.Height();
        }

        // set the size of treelistbox
        m_pTreeView->SetPosSizePixel( aTreeViewPos, aTreeViewSize );

        //set the size of the splitter
        m_pSplitter->SetPosSizePixel( aSplitPos, Size( aSplitSize.Width(), aPlaygroundSize.Height() ) );
        m_pSplitter->SetDragRectPixel( _rPlayground );
    }

    // set the size of grid control
    Reference< ::com::sun::star::awt::XWindow >  xGridAsWindow(m_xGrid, UNO_QUERY);
    if (xGridAsWindow.is())
        xGridAsWindow->setPosSize( aSplitPos.X() + aSplitSize.Width(), aPlaygroundPos.Y(),
                                   aPlaygroundSize.Width() - aSplitSize.Width() - aSplitPos.X(), aPlaygroundSize.Height(), ::com::sun::star::awt::PosSize::POSSIZE);

    // just for completeness: there is no space left, we occupied it all ...
    _rPlayground.SetPos( _rPlayground.BottomRight() );
    _rPlayground.SetSize( Size( 0, 0 ) );
}

//------------------------------------------------------------------
sal_uInt16 UnoDataBrowserView::View2ModelPos(sal_uInt16 nPos) const
{
    return m_pVclControl ? m_pVclControl->GetModelColumnPos(m_pVclControl->GetColumnIdFromViewPos(nPos)) : -1;
}

// -----------------------------------------------------------------------------
SbaGridControl* UnoDataBrowserView::getVclControl() const
{
    if ( !m_pVclControl )
    {
        OSL_ENSURE(m_xGrid.is(),"Grid not set!");
        if ( m_xGrid.is() )
        {
            Reference< ::com::sun::star::awt::XWindowPeer >  xPeer = m_xGrid->getPeer();
            if ( xPeer.is() )
            {
                SbaXGridPeer* pPeer = SbaXGridPeer::getImplementation(xPeer);
                UnoDataBrowserView* pTHIS = const_cast<UnoDataBrowserView*>(this);
                if ( pPeer )
                {
                    m_pVclControl = static_cast<SbaGridControl*>(pPeer->GetWindow());
                    pTHIS->startComponentListening(Reference<XComponent>(VCLUnoHelper::GetInterface(m_pVclControl),UNO_QUERY));
                }
            }
        }
    }
    return m_pVclControl;
}
// -----------------------------------------------------------------------------
void UnoDataBrowserView::GetFocus()
{
    ODataView::GetFocus();
    if( m_pTreeView && m_pTreeView->IsVisible() && !m_pTreeView->HasChildPathFocus())
        m_pTreeView->GrabFocus();
    else if (m_pVclControl && m_xGrid.is())
    {
        sal_Bool bGrabFocus = sal_False;
        if(!m_pVclControl->HasChildPathFocus())
        {
            bGrabFocus = isGrabVclControlFocusAllowed(this);
            if( bGrabFocus )
                m_pVclControl->GrabFocus();
        }
        if(!bGrabFocus && m_pTreeView && m_pTreeView->IsVisible() )
            m_pTreeView->GrabFocus();
    }
}
// -----------------------------------------------------------------------------
void UnoDataBrowserView::_disposing( const ::com::sun::star::lang::EventObject& /*_rSource*/ )
{
    stopComponentListening(Reference<XComponent>(VCLUnoHelper::GetInterface(m_pVclControl),UNO_QUERY));
    m_pVclControl = NULL;
}
// -------------------------------------------------------------------------
long UnoDataBrowserView::PreNotify( NotifyEvent& rNEvt )
{
    long nDone = 0L;
    if(rNEvt.GetType() == EVENT_KEYINPUT)
    {
        sal_Bool bGrabAllowed = isGrabVclControlFocusAllowed(this);
        if ( bGrabAllowed )
        {
            const KeyEvent* pKeyEvt = rNEvt.GetKeyEvent();
            const KeyCode& rKeyCode = pKeyEvt->GetKeyCode();
            if (  ( rKeyCode == KeyCode( KEY_E, TRUE, TRUE, FALSE ) )
               || ( rKeyCode == KeyCode( KEY_TAB, TRUE, FALSE, FALSE ) )
               )
            {
                if ( m_pTreeView && m_pVclControl && m_pTreeView->HasChildPathFocus() )
                    m_pVclControl->GrabFocus();
                else if ( m_pTreeView && m_pVclControl && m_pVclControl->HasChildPathFocus() )
                    m_pTreeView->GrabFocus();

                nDone = 1L;
            }
        }
    }
    return nDone ? nDone : ODataView::PreNotify(rNEvt);
}

DBG_NAME(BrowserViewStatusDisplay)
// -----------------------------------------------------------------------------
BrowserViewStatusDisplay::BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const String& _rStatus )
    :m_pView(_pView)
{
    DBG_CTOR(BrowserViewStatusDisplay,NULL);

    if (m_pView)
        m_pView->showStatus(_rStatus);
}

// -----------------------------------------------------------------------------
BrowserViewStatusDisplay::~BrowserViewStatusDisplay( )
{
    if (m_pView)
        m_pView->showStatus(String());

    DBG_DTOR(BrowserViewStatusDisplay,NULL);
}
// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "partial_update.h"
#include <vespa/vespalib/util/overload.h>
#include <vespa/vespalib/util/typify.h>
#include <vespa/vespalib/util/visit_ranges.h>
#include <cassert>
#include <set>

#include <vespa/log/log.h>
LOG_SETUP(".eval.tensor.partial_update");

using namespace vespalib::eval;

namespace vespalib::tensor {

namespace {

using join_fun_t = double (*)(double, double);

static constexpr size_t npos() { return -1; }

enum class DimCase {
    SKIP_MAPPED, SKIP_INDEXED,
    MISSING_MAPPED, MISSING_INDEXED,
    MAPPED_MATCH, INDEXED_MATCH,
    CONV_TO_INDEXED, CONV_TO_MAPPED
};

struct DenseCoords {
    std::vector<size_t> dim_sizes;
    std::vector<const char *> dim_names;
    size_t total_size = 1;
    size_t offset;
    size_t dim;
    void clear() { offset = 0; dim = 0; }
    void with(size_t coord) {
        size_t cur = dim_sizes[dim];
        if (coord < cur) {
            if (offset != npos()) {
                offset *= cur;
                offset += coord;
            }
        } else {
            // "bad label{%s} in modifier tensor, was %zu, must be < %zu", dim_names[dim], coord, cur
            offset = npos();
        }
        ++dim;
    }
    void with(vespalib::stringref label) {
        uint32_t result = 0;
        for (char c : label) {
            if (c < '0' || c > '9') { // bad char
                // "bad label{%s} in modifier tensor, was '%s'", dim_names[dim], label.data()
                offset = npos();
                ++dim;
                return;
            }
            result = result * 10 + (c - '0');
        }
        with(result);
    }
    void add_dim(const char *name, size_t sz) {
        dim_sizes.push_back(sz);
        dim_names.push_back(name);
        total_size *= sz;
    }
    size_t get() const {
        assert(dim == dim_sizes.size());
        return offset;
    }
    ~DenseCoords();
};
DenseCoords::~DenseCoords() = default;

struct Addresses {
    std::vector<vespalib::stringref> addr;
    std::vector<vespalib::stringref *> next_result_refs;
    std::vector<const vespalib::stringref *> lookup_refs;
    std::vector<size_t> lookup_view_dims;
    Addresses(size_t sz)
        : addr(sz), next_result_refs(sz), lookup_refs(sz), lookup_view_dims(sz)
    {
        for (size_t i = 0; i < sz; ++i) {
            next_result_refs[i] = &addr[i];
            lookup_refs[i] = &addr[i];
            lookup_view_dims[i] = i;
        }
    }
    ~Addresses();
};
Addresses::~Addresses() = default;

struct AddressHandler {
    std::vector<DimCase> how;
    DenseCoords target_coords;
    Addresses for_output;
    Addresses from_modifier;
    bool valid;

    AddressHandler(const ValueType &input_type,
                const ValueType &modifier_type)
        : how(), target_coords(),
          for_output(input_type.count_mapped_dimensions()),
          from_modifier(modifier_type.count_mapped_dimensions()),
          valid(true)
    {
        if (! modifier_type.is_sparse()) {
            LOG(error, "Unexpected non-sparse modifier tensor, type is %s",
                modifier_type.to_spec().c_str());
            valid = false;
            return;
        }
        // analyse dimensions
        auto visitor = overload {
            [&](visit_ranges_either, const auto &) { valid = false; },
            [&](visit_ranges_both, const auto &a, const auto &) {
                how.push_back(a.is_mapped() ? DimCase::MAPPED_MATCH : DimCase::CONV_TO_INDEXED);
            }
        };
        const auto & input_dims = input_type.dimensions();
        const auto & modifier_dims = modifier_type.dimensions();
        visit_ranges(visitor,
                     input_dims.begin(), input_dims.end(),
                     modifier_dims.begin(), modifier_dims.end(),
                     [](const auto &a, const auto &b){ return (a.name < b.name); });
        if ((! valid) ||
            (input_dims.size() != modifier_dims.size()) ||
            (input_dims.size() != how.size()))
        {
            LOG(error, "Value type %s does not match modifier type %s (should have same dimensions)",
                input_type.to_spec().c_str(),
                modifier_type.to_spec().c_str());
            valid = false;
            return;
        }
        for (const auto & dim : input_type.dimensions()) {
            if (dim.is_indexed()) {
                target_coords.add_dim(dim.name.c_str(), dim.size);
            }
        }
    }

    void handle_address()
    {
        target_coords.clear();
        auto out = for_output.addr.begin();
        for (size_t i = 0; i < how.size(); ++i) {
            if (how[i] == DimCase::CONV_TO_INDEXED) {
                target_coords.with(from_modifier.addr[i]);
            } else {
                *out++ = from_modifier.addr[i];
            }
        }
        assert(out == for_output.addr.end());
        assert(target_coords.dim == target_coords.dim_sizes.size());
    }

    ~AddressHandler();
};
AddressHandler::~AddressHandler() = default;

template <typename CT>
Value::UP
copy_tensor(const Value &input, const ValueType &input_type, Addresses &helper, const ValueBuilderFactory &factory)
{
    const size_t num_mapped_in_input = input_type.count_mapped_dimensions();
    const size_t dsss = input_type.dense_subspace_size();
    const size_t expected_subspaces = input.index().size();
    auto builder = factory.create_value_builder<CT>(input_type, num_mapped_in_input, dsss, expected_subspaces);
    auto view = input.index().create_view({});
    view->lookup({});
    auto input_cells = input.cells().typify<CT>();
    size_t input_subspace;
    while (view->next_result(helper.next_result_refs, input_subspace)) {
        size_t input_offset = input_subspace * dsss;
        auto src = input_cells.begin() + input_offset;
        auto dst = builder->add_subspace(helper.addr).begin();
        for (size_t i = 0; i < dsss; ++i) {
            dst[i] = src[i];
        }
    }
    return builder->build(std::move(builder));
}

template <typename ICT, typename MCT>
Value::UP
my_modify_value(const Value &input, join_fun_t function, const Value &modifier, const ValueBuilderFactory &factory)
{
    const ValueType &input_type = input.type();
    const size_t dsss = input_type.dense_subspace_size();
    const ValueType &modifier_type = modifier.type();
    AddressHandler handler(input_type, modifier_type);
    if (! handler.valid) {
        return Value::UP();
    }
    // copy input to output
    auto out = copy_tensor<ICT>(input, input_type, handler.for_output, factory);
    // need to overwrite some cells
    auto output_cells = unconstify(out->cells().template typify<ICT>());
    const auto modifier_cells = modifier.cells().typify<MCT>();
    auto modifier_view = modifier.index().create_view({});
    auto lookup_view = out->index().create_view(handler.for_output.lookup_view_dims);
    modifier_view->lookup({});
    size_t modifier_subspace_index;
    while (modifier_view->next_result(handler.from_modifier.next_result_refs, modifier_subspace_index)) {
        handler.handle_address();
        size_t dense_idx = handler.target_coords.get();
        if (dense_idx == npos()) {
            continue;
        }
        lookup_view->lookup(handler.for_output.lookup_refs);
        size_t output_subspace_index;
        if (lookup_view->next_result({}, output_subspace_index)) {
            size_t subspace_offset = dsss * output_subspace_index;
            auto dst = output_cells.begin() + subspace_offset;
            ICT lhs = dst[dense_idx];
            MCT rhs = modifier_cells[modifier_subspace_index];
            dst[dense_idx] = function(lhs, rhs);
        }
    }
    return out;
}
struct PerformModify {
    template<typename ICT, typename MCT>
    static Value::UP invoke(const Value &input,
                            join_fun_t function,
                            const Value &modifier,
                            const ValueBuilderFactory &factory)
    {
        return my_modify_value<ICT,MCT>(input, function, modifier, factory);
    }
};

//-----------------------------------------------------------------------------

template <typename ICT, typename MCT>
Value::UP
my_add_cells(const Value &input, const Value &modifier, const ValueBuilderFactory &factory)
{
    const ValueType &input_type = input.type();
    const ValueType &modifier_type = modifier.type();
    if (input_type.dimensions() != modifier_type.dimensions()) {
        LOG(error, "when adding cells to a tensor, dimensions must be equal");
        return Value::UP();
    }
    const auto input_cells = input.cells().typify<ICT>();
    const auto modifier_cells = modifier.cells().typify<MCT>();
    const size_t num_mapped_in_input = input_type.count_mapped_dimensions();
    const size_t dsss = input_type.dense_subspace_size();
    const size_t expected_subspaces = input.index().size() + modifier.index().size();
    auto builder = factory.create_value_builder<ICT>(input_type, num_mapped_in_input, dsss, expected_subspaces);
    Addresses addrs(num_mapped_in_input);
    std::set<size_t> overwritten_subspaces;
    auto modifier_view = modifier.index().create_view({});
    auto lookup_view = input.index().create_view(addrs.lookup_view_dims);
    modifier_view->lookup({});
    size_t modifier_subspace_index;
    while (modifier_view->next_result(addrs.next_result_refs, modifier_subspace_index)) {
        size_t modifier_offset = dsss * modifier_subspace_index;
        auto src = modifier_cells.begin() + modifier_offset;
        auto dst = builder->add_subspace(addrs.addr).begin();
        for (size_t i = 0; i < dsss; ++i) {
            dst[i] = src[i];
        }
        lookup_view->lookup(addrs.lookup_refs);
        size_t input_subspace_index;
        if (lookup_view->next_result({}, input_subspace_index)) {
            overwritten_subspaces.insert(input_subspace_index);
        }
    }
    auto input_view = input.index().create_view({});
    input_view->lookup({});
    size_t input_subspace_index;
    while (input_view->next_result(addrs.next_result_refs, input_subspace_index)) {
        if (overwritten_subspaces.count(input_subspace_index) == 0) {
            size_t input_offset = dsss * input_subspace_index;
            auto src = input_cells.begin() + input_offset;
            auto dst = builder->add_subspace(addrs.addr).begin();
            for (size_t i = 0; i < dsss; ++i) {
                dst[i] = src[i];
            }
        }
    }
    return builder->build(std::move(builder));
}

struct PerformAdd {
    template<typename ICT, typename MCT>
    static Value::UP invoke(const Value &input,
                            const Value &modifier,
                            const ValueBuilderFactory &factory)
    {
        return my_add_cells<ICT,MCT>(input, modifier, factory);
    }
};

//-----------------------------------------------------------------------------

template <typename ICT>
Value::UP
my_remove_cells(const Value &input, const Value &modifier, const ValueBuilderFactory &factory)
{
    const ValueType &input_type = input.type();
    const ValueType &modifier_type = modifier.type();
    if (input_type.mapped_dimensions() != modifier_type.mapped_dimensions()) {
        LOG(error, "when removing cells from a tensor, mapped dimensions must be equal");
        return Value::UP();
    }
    if (input_type.mapped_dimensions().size() == 0) {
        LOG(error, "cannot remove cells from a dense tensor");
        return Value::UP();
    }
    const auto input_cells = input.cells().typify<ICT>();
    const size_t num_mapped_in_input = input_type.count_mapped_dimensions();
    const size_t dsss = input_type.dense_subspace_size();
    Addresses addrs(num_mapped_in_input);
    std::set<size_t> removed_subspaces;
    auto modifier_view = modifier.index().create_view({});
    auto lookup_view = input.index().create_view(addrs.lookup_view_dims);
    modifier_view->lookup({});
    size_t modifier_subspace_index;
    while (modifier_view->next_result(addrs.next_result_refs, modifier_subspace_index)) {
        lookup_view->lookup(addrs.lookup_refs);
        size_t input_subspace_index;
        if (lookup_view->next_result({}, input_subspace_index)) {
            removed_subspaces.insert(input_subspace_index);
        }
    }
    const size_t expected_subspaces = input.index().size() - removed_subspaces.size();
    auto builder = factory.create_value_builder<ICT>(input_type, num_mapped_in_input, dsss, expected_subspaces);
    auto input_view = input.index().create_view({});
    input_view->lookup({});
    size_t input_subspace_index;
    while (input_view->next_result(addrs.next_result_refs, input_subspace_index)) {
        if (removed_subspaces.count(input_subspace_index) == 0) {
            size_t input_offset = dsss * input_subspace_index;
            auto src = input_cells.begin() + input_offset;
            auto dst = builder->add_subspace(addrs.addr).begin();
            for (size_t i = 0; i < dsss; ++i) {
                dst[i] = src[i];
            }
        }
    }
    return builder->build(std::move(builder));
}

struct PerformRemove {
    template<typename ICT>
    static Value::UP invoke(const Value &input,
                            const Value &modifier,
                            const ValueBuilderFactory &factory)
    {
        return my_remove_cells<ICT>(input, modifier, factory);
    }
};

} // namespace <unnamed>

//-----------------------------------------------------------------------------

Value::UP
TensorPartialUpdate::modify(const Value &input, join_fun_t function,
                            const Value &modifier, const ValueBuilderFactory &factory)
{
    return typify_invoke<2, TypifyCellType, PerformModify>(
            input.cells().type, modifier.cells().type,
            input, function, modifier, factory);
}

Value::UP
TensorPartialUpdate::add(const Value &input, const Value &add_cells, const ValueBuilderFactory &factory)
{
    return typify_invoke<2, TypifyCellType, PerformAdd>(
            input.cells().type, add_cells.cells().type,
            input, add_cells, factory);
}

Value::UP
TensorPartialUpdate::remove(const Value &input, const Value &remove_spec, const ValueBuilderFactory &factory)
{
    return typify_invoke<1, TypifyCellType, PerformRemove>(
            input.cells().type,
            input, remove_spec, factory);
}

} // namespace
<commit_msg>only keep DimCase enums that are possible (within current constraints)<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "partial_update.h"
#include <vespa/vespalib/util/overload.h>
#include <vespa/vespalib/util/typify.h>
#include <vespa/vespalib/util/visit_ranges.h>
#include <cassert>
#include <set>

#include <vespa/log/log.h>
LOG_SETUP(".eval.tensor.partial_update");

using namespace vespalib::eval;

namespace vespalib::tensor {

namespace {

using join_fun_t = double (*)(double, double);

static constexpr size_t npos() { return -1; }

enum class DimCase {
    MAPPED_MATCH, CONV_TO_INDEXED
};

struct DenseCoords {
    std::vector<size_t> dim_sizes;
    std::vector<const char *> dim_names;
    size_t total_size = 1;
    size_t offset;
    size_t dim;
    void clear() { offset = 0; dim = 0; }
    void with(size_t coord) {
        size_t cur = dim_sizes[dim];
        if (coord < cur) {
            if (offset != npos()) {
                offset *= cur;
                offset += coord;
            }
        } else {
            // "bad label{%s} in modifier tensor, was %zu, must be < %zu", dim_names[dim], coord, cur
            offset = npos();
        }
        ++dim;
    }
    void with(vespalib::stringref label) {
        uint32_t result = 0;
        for (char c : label) {
            if (c < '0' || c > '9') { // bad char
                // "bad label{%s} in modifier tensor, was '%s'", dim_names[dim], label.data()
                offset = npos();
                ++dim;
                return;
            }
            result = result * 10 + (c - '0');
        }
        with(result);
    }
    void add_dim(const char *name, size_t sz) {
        dim_sizes.push_back(sz);
        dim_names.push_back(name);
        total_size *= sz;
    }
    size_t get() const {
        assert(dim == dim_sizes.size());
        return offset;
    }
    ~DenseCoords();
};
DenseCoords::~DenseCoords() = default;

struct Addresses {
    std::vector<vespalib::stringref> addr;
    std::vector<vespalib::stringref *> next_result_refs;
    std::vector<const vespalib::stringref *> lookup_refs;
    std::vector<size_t> lookup_view_dims;
    Addresses(size_t sz)
        : addr(sz), next_result_refs(sz), lookup_refs(sz), lookup_view_dims(sz)
    {
        for (size_t i = 0; i < sz; ++i) {
            next_result_refs[i] = &addr[i];
            lookup_refs[i] = &addr[i];
            lookup_view_dims[i] = i;
        }
    }
    ~Addresses();
};
Addresses::~Addresses() = default;

struct AddressHandler {
    std::vector<DimCase> how;
    DenseCoords target_coords;
    Addresses for_output;
    Addresses from_modifier;
    bool valid;

    AddressHandler(const ValueType &input_type,
                const ValueType &modifier_type)
        : how(), target_coords(),
          for_output(input_type.count_mapped_dimensions()),
          from_modifier(modifier_type.count_mapped_dimensions()),
          valid(true)
    {
        if (! modifier_type.is_sparse()) {
            LOG(error, "Unexpected non-sparse modifier tensor, type is %s",
                modifier_type.to_spec().c_str());
            valid = false;
            return;
        }
        // analyse dimensions
        auto visitor = overload {
            [&](visit_ranges_either, const auto &) { valid = false; },
            [&](visit_ranges_both, const auto &a, const auto &) {
                how.push_back(a.is_mapped() ? DimCase::MAPPED_MATCH : DimCase::CONV_TO_INDEXED);
            }
        };
        const auto & input_dims = input_type.dimensions();
        const auto & modifier_dims = modifier_type.dimensions();
        visit_ranges(visitor,
                     input_dims.begin(), input_dims.end(),
                     modifier_dims.begin(), modifier_dims.end(),
                     [](const auto &a, const auto &b){ return (a.name < b.name); });
        if ((! valid) ||
            (input_dims.size() != modifier_dims.size()) ||
            (input_dims.size() != how.size()))
        {
            LOG(error, "Value type %s does not match modifier type %s (should have same dimensions)",
                input_type.to_spec().c_str(),
                modifier_type.to_spec().c_str());
            valid = false;
            return;
        }
        for (const auto & dim : input_type.dimensions()) {
            if (dim.is_indexed()) {
                target_coords.add_dim(dim.name.c_str(), dim.size);
            }
        }
    }

    void handle_address()
    {
        target_coords.clear();
        auto out = for_output.addr.begin();
        for (size_t i = 0; i < how.size(); ++i) {
            if (how[i] == DimCase::CONV_TO_INDEXED) {
                target_coords.with(from_modifier.addr[i]);
            } else {
                *out++ = from_modifier.addr[i];
            }
        }
        assert(out == for_output.addr.end());
        assert(target_coords.dim == target_coords.dim_sizes.size());
    }

    ~AddressHandler();
};
AddressHandler::~AddressHandler() = default;

template <typename CT>
Value::UP
copy_tensor(const Value &input, const ValueType &input_type, Addresses &helper, const ValueBuilderFactory &factory)
{
    const size_t num_mapped_in_input = input_type.count_mapped_dimensions();
    const size_t dsss = input_type.dense_subspace_size();
    const size_t expected_subspaces = input.index().size();
    auto builder = factory.create_value_builder<CT>(input_type, num_mapped_in_input, dsss, expected_subspaces);
    auto view = input.index().create_view({});
    view->lookup({});
    auto input_cells = input.cells().typify<CT>();
    size_t input_subspace;
    while (view->next_result(helper.next_result_refs, input_subspace)) {
        size_t input_offset = input_subspace * dsss;
        auto src = input_cells.begin() + input_offset;
        auto dst = builder->add_subspace(helper.addr).begin();
        for (size_t i = 0; i < dsss; ++i) {
            dst[i] = src[i];
        }
    }
    return builder->build(std::move(builder));
}

template <typename ICT, typename MCT>
Value::UP
my_modify_value(const Value &input, join_fun_t function, const Value &modifier, const ValueBuilderFactory &factory)
{
    const ValueType &input_type = input.type();
    const size_t dsss = input_type.dense_subspace_size();
    const ValueType &modifier_type = modifier.type();
    AddressHandler handler(input_type, modifier_type);
    if (! handler.valid) {
        return Value::UP();
    }
    // copy input to output
    auto out = copy_tensor<ICT>(input, input_type, handler.for_output, factory);
    // need to overwrite some cells
    auto output_cells = unconstify(out->cells().template typify<ICT>());
    const auto modifier_cells = modifier.cells().typify<MCT>();
    auto modifier_view = modifier.index().create_view({});
    auto lookup_view = out->index().create_view(handler.for_output.lookup_view_dims);
    modifier_view->lookup({});
    size_t modifier_subspace_index;
    while (modifier_view->next_result(handler.from_modifier.next_result_refs, modifier_subspace_index)) {
        handler.handle_address();
        size_t dense_idx = handler.target_coords.get();
        if (dense_idx == npos()) {
            continue;
        }
        lookup_view->lookup(handler.for_output.lookup_refs);
        size_t output_subspace_index;
        if (lookup_view->next_result({}, output_subspace_index)) {
            size_t subspace_offset = dsss * output_subspace_index;
            auto dst = output_cells.begin() + subspace_offset;
            ICT lhs = dst[dense_idx];
            MCT rhs = modifier_cells[modifier_subspace_index];
            dst[dense_idx] = function(lhs, rhs);
        }
    }
    return out;
}
struct PerformModify {
    template<typename ICT, typename MCT>
    static Value::UP invoke(const Value &input,
                            join_fun_t function,
                            const Value &modifier,
                            const ValueBuilderFactory &factory)
    {
        return my_modify_value<ICT,MCT>(input, function, modifier, factory);
    }
};

//-----------------------------------------------------------------------------

template <typename ICT, typename MCT>
Value::UP
my_add_cells(const Value &input, const Value &modifier, const ValueBuilderFactory &factory)
{
    const ValueType &input_type = input.type();
    const ValueType &modifier_type = modifier.type();
    if (input_type.dimensions() != modifier_type.dimensions()) {
        LOG(error, "when adding cells to a tensor, dimensions must be equal");
        return Value::UP();
    }
    const auto input_cells = input.cells().typify<ICT>();
    const auto modifier_cells = modifier.cells().typify<MCT>();
    const size_t num_mapped_in_input = input_type.count_mapped_dimensions();
    const size_t dsss = input_type.dense_subspace_size();
    const size_t expected_subspaces = input.index().size() + modifier.index().size();
    auto builder = factory.create_value_builder<ICT>(input_type, num_mapped_in_input, dsss, expected_subspaces);
    Addresses addrs(num_mapped_in_input);
    std::set<size_t> overwritten_subspaces;
    auto modifier_view = modifier.index().create_view({});
    auto lookup_view = input.index().create_view(addrs.lookup_view_dims);
    modifier_view->lookup({});
    size_t modifier_subspace_index;
    while (modifier_view->next_result(addrs.next_result_refs, modifier_subspace_index)) {
        size_t modifier_offset = dsss * modifier_subspace_index;
        auto src = modifier_cells.begin() + modifier_offset;
        auto dst = builder->add_subspace(addrs.addr).begin();
        for (size_t i = 0; i < dsss; ++i) {
            dst[i] = src[i];
        }
        lookup_view->lookup(addrs.lookup_refs);
        size_t input_subspace_index;
        if (lookup_view->next_result({}, input_subspace_index)) {
            overwritten_subspaces.insert(input_subspace_index);
        }
    }
    auto input_view = input.index().create_view({});
    input_view->lookup({});
    size_t input_subspace_index;
    while (input_view->next_result(addrs.next_result_refs, input_subspace_index)) {
        if (overwritten_subspaces.count(input_subspace_index) == 0) {
            size_t input_offset = dsss * input_subspace_index;
            auto src = input_cells.begin() + input_offset;
            auto dst = builder->add_subspace(addrs.addr).begin();
            for (size_t i = 0; i < dsss; ++i) {
                dst[i] = src[i];
            }
        }
    }
    return builder->build(std::move(builder));
}

struct PerformAdd {
    template<typename ICT, typename MCT>
    static Value::UP invoke(const Value &input,
                            const Value &modifier,
                            const ValueBuilderFactory &factory)
    {
        return my_add_cells<ICT,MCT>(input, modifier, factory);
    }
};

//-----------------------------------------------------------------------------

template <typename ICT>
Value::UP
my_remove_cells(const Value &input, const Value &modifier, const ValueBuilderFactory &factory)
{
    const ValueType &input_type = input.type();
    const ValueType &modifier_type = modifier.type();
    if (input_type.mapped_dimensions() != modifier_type.mapped_dimensions()) {
        LOG(error, "when removing cells from a tensor, mapped dimensions must be equal");
        return Value::UP();
    }
    if (input_type.mapped_dimensions().size() == 0) {
        LOG(error, "cannot remove cells from a dense tensor");
        return Value::UP();
    }
    const auto input_cells = input.cells().typify<ICT>();
    const size_t num_mapped_in_input = input_type.count_mapped_dimensions();
    const size_t dsss = input_type.dense_subspace_size();
    Addresses addrs(num_mapped_in_input);
    std::set<size_t> removed_subspaces;
    auto modifier_view = modifier.index().create_view({});
    auto lookup_view = input.index().create_view(addrs.lookup_view_dims);
    modifier_view->lookup({});
    size_t modifier_subspace_index;
    while (modifier_view->next_result(addrs.next_result_refs, modifier_subspace_index)) {
        lookup_view->lookup(addrs.lookup_refs);
        size_t input_subspace_index;
        if (lookup_view->next_result({}, input_subspace_index)) {
            removed_subspaces.insert(input_subspace_index);
        }
    }
    const size_t expected_subspaces = input.index().size() - removed_subspaces.size();
    auto builder = factory.create_value_builder<ICT>(input_type, num_mapped_in_input, dsss, expected_subspaces);
    auto input_view = input.index().create_view({});
    input_view->lookup({});
    size_t input_subspace_index;
    while (input_view->next_result(addrs.next_result_refs, input_subspace_index)) {
        if (removed_subspaces.count(input_subspace_index) == 0) {
            size_t input_offset = dsss * input_subspace_index;
            auto src = input_cells.begin() + input_offset;
            auto dst = builder->add_subspace(addrs.addr).begin();
            for (size_t i = 0; i < dsss; ++i) {
                dst[i] = src[i];
            }
        }
    }
    return builder->build(std::move(builder));
}

struct PerformRemove {
    template<typename ICT>
    static Value::UP invoke(const Value &input,
                            const Value &modifier,
                            const ValueBuilderFactory &factory)
    {
        return my_remove_cells<ICT>(input, modifier, factory);
    }
};

} // namespace <unnamed>

//-----------------------------------------------------------------------------

Value::UP
TensorPartialUpdate::modify(const Value &input, join_fun_t function,
                            const Value &modifier, const ValueBuilderFactory &factory)
{
    return typify_invoke<2, TypifyCellType, PerformModify>(
            input.cells().type, modifier.cells().type,
            input, function, modifier, factory);
}

Value::UP
TensorPartialUpdate::add(const Value &input, const Value &add_cells, const ValueBuilderFactory &factory)
{
    return typify_invoke<2, TypifyCellType, PerformAdd>(
            input.cells().type, add_cells.cells().type,
            input, add_cells, factory);
}

Value::UP
TensorPartialUpdate::remove(const Value &input, const Value &remove_spec, const ValueBuilderFactory &factory)
{
    return typify_invoke<1, TypifyCellType, PerformRemove>(
            input.cells().type,
            input, remove_spec, factory);
}

} // namespace
<|endoftext|>


<commit_before>#include "utest.h"
#include "builder.h"
#include "trainer.h"
#include "accumulator.h"
#include "math/epsilon.h"
#include "solver_batch.h"
#include "tasks/task_affine.h"

using namespace nano;

NANO_BEGIN_MODULE(trainer_batch)

NANO_CASE(tune_and_train_regression)
{
        const auto isize = 5;
        const auto osize = 3;
        const auto fold = 0;

        // create synthetic task
        const auto task = get_tasks().get("synth-affine");
        NANO_REQUIRE(task);
        task->config(json_writer_t().object(
                "isize", isize, "osize", osize, "noise", 0, "count", 100, "type", affine_task_type::regression).str());
        NANO_REQUIRE(task->load());

        // create default enhancer (use task as it is)
        const auto enhancer = get_enhancers().get("default");
        NANO_REQUIRE(enhancer);

        // create loss
        const auto loss = get_losses().get("square");
        NANO_REQUIRE(loss);

        // create model
        model_t model;
        NANO_REQUIRE(make_linear(model, osize, 1, 1, "act-snorm"));
        NANO_REQUIRE(model.done());
        NANO_REQUIRE(model.resize(make_dims(isize, 1, 1), make_dims(osize, 1, 1)));

        // create batch trainer
        const auto trainer = get_trainers().get("batch");
        NANO_REQUIRE(trainer);

        // check that the trainer works for all compatible solvers
        for (const auto& solver : get_batch_solvers().ids())
        {
                trainer->config(json_writer_t().object(
                        "epochs", 128, "solver", solver, "eps", epsilon0<scalar_t>()).str());

                accumulator_t acc(model, *loss);
                acc.threads(1);

                acc.random();
                trainer->tune(*enhancer, *task, fold, acc);

                acc.random();
                const auto result = trainer->train(*enhancer, *task, fold, acc);
                NANO_REQUIRE(result);
                const auto state = result.optimum_state();

                NANO_CHECK_LESS(state.m_train.m_error, epsilon1<scalar_t>());
        }
}

NANO_CASE(tune_and_train_classification)
{
        const auto isize = 3;
        const auto osize = 2;
        const auto fold = 0;

        // create synthetic task
        const auto task = get_tasks().get("synth-affine");
        NANO_REQUIRE(task);
        task->config(json_writer_t().object(
                "isize", isize, "osize", osize, "noise", 0, "count", 1000, "type", affine_task_type::classification).str());
        NANO_REQUIRE(task->load());

        // create default enhancer (use task as it is)
        const auto enhancer = get_enhancers().get("default");
        NANO_REQUIRE(enhancer);

        // create loss
        const auto loss = get_losses().get("m-exponential");
        NANO_REQUIRE(loss);

        // create model
        model_t model;
        NANO_REQUIRE(make_linear(model, osize, 1, 1, "act-snorm"));
        NANO_REQUIRE(model.done());
        NANO_REQUIRE(model.resize(make_dims(isize, 1, 1), make_dims(osize, 1, 1)));

        // create batch trainer
        const auto trainer = get_trainers().get("batch");
        NANO_REQUIRE(trainer);

        // check that the trainer works for all compatible solvers
        for (const auto& solver : get_batch_solvers().ids())
        {
                trainer->config(json_writer_t().object(
                        "epochs", 1024, "solver", solver, "eps", epsilon1<scalar_t>()).str());

                accumulator_t acc(model, *loss);
                acc.threads(1);

                acc.random();
                trainer->tune(*enhancer, *task, fold, acc);

                acc.random();
                const auto result = trainer->train(*enhancer, *task, fold, acc);
                NANO_REQUIRE(result);
                const auto state = result.optimum_state();

                NANO_CHECK_LESS(state.m_train.m_error, epsilon3<scalar_t>());
        }
}

NANO_END_MODULE()
<commit_msg>faster unit test for batch trainers<commit_after>#include "utest.h"
#include "builder.h"
#include "trainer.h"
#include "accumulator.h"
#include "math/epsilon.h"
#include "solver_batch.h"
#include "tasks/task_affine.h"

using namespace nano;

NANO_BEGIN_MODULE(trainer_batch)

NANO_CASE(tune_and_train_regression)
{
        const auto isize = 5;
        const auto osize = 3;
        const auto fold = 0;

        // create synthetic task
        const auto task = get_tasks().get("synth-affine");
        NANO_REQUIRE(task);
        task->config(json_writer_t().object(
                "isize", isize, "osize", osize, "noise", 0, "count", 100, "type", affine_task_type::regression).str());
        NANO_REQUIRE(task->load());

        // create default enhancer (use task as it is)
        const auto enhancer = get_enhancers().get("default");
        NANO_REQUIRE(enhancer);

        // create loss
        const auto loss = get_losses().get("square");
        NANO_REQUIRE(loss);

        // create model
        model_t model;
        NANO_REQUIRE(make_linear(model, osize, 1, 1, "act-snorm"));
        NANO_REQUIRE(model.done());
        NANO_REQUIRE(model.resize(make_dims(isize, 1, 1), make_dims(osize, 1, 1)));

        // create batch trainer
        const auto trainer = get_trainers().get("batch");
        NANO_REQUIRE(trainer);

        // check that the trainer works for all compatible solvers
        for (const auto& solver : get_batch_solvers().ids())
        {
                trainer->config(json_writer_t().object(
                        "epochs", 128, "solver", solver, "eps", epsilon0<scalar_t>()).str());

                accumulator_t acc(model, *loss);
                acc.threads(1);

                acc.random();
                trainer->tune(*enhancer, *task, fold, acc);

                acc.random();
                const auto result = trainer->train(*enhancer, *task, fold, acc);
                NANO_REQUIRE(result);
                const auto state = result.optimum_state();

                NANO_CHECK_LESS(state.m_train.m_error, epsilon1<scalar_t>());
        }
}

NANO_CASE(tune_and_train_classification)
{
        const auto isize = 3;
        const auto osize = 2;
        const auto fold = 0;

        // create synthetic task
        const auto task = get_tasks().get("synth-affine");
        NANO_REQUIRE(task);
        task->config(json_writer_t().object(
                "isize", isize, "osize", osize, "noise", 0, "count", 100, "type", affine_task_type::classification).str());
        NANO_REQUIRE(task->load());

        // create default enhancer (use task as it is)
        const auto enhancer = get_enhancers().get("default");
        NANO_REQUIRE(enhancer);

        // create loss
        const auto loss = get_losses().get("m-exponential");
        NANO_REQUIRE(loss);

        // create model
        model_t model;
        NANO_REQUIRE(make_linear(model, osize, 1, 1, "act-snorm"));
        NANO_REQUIRE(model.done());
        NANO_REQUIRE(model.resize(make_dims(isize, 1, 1), make_dims(osize, 1, 1)));

        // create batch trainer
        const auto trainer = get_trainers().get("batch");
        NANO_REQUIRE(trainer);

        // check that the trainer works for all compatible solvers
        for (const auto& solver : get_batch_solvers().ids())
        {
                trainer->config(json_writer_t().object(
                        "epochs", 128, "solver", solver, "eps", epsilon0<scalar_t>()).str());

                accumulator_t acc(model, *loss);
                acc.threads(1);

                acc.random();
                trainer->tune(*enhancer, *task, fold, acc);

                acc.random();
                const auto result = trainer->train(*enhancer, *task, fold, acc);
                NANO_REQUIRE(result);
                const auto state = result.optimum_state();

                NANO_CHECK_LESS(state.m_train.m_error, epsilon1<scalar_t>());
        }
}

NANO_END_MODULE()
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2020 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 "call/version.h"

namespace webrtc {

// The timestamp is always in UTC.
const char* const kSourceTimestamp = "WebRTC source stamp 2021-01-03T04:03:33";

void LoadWebRTCVersionInRegister() {
  // Using volatile to instruct the compiler to not optimize `p` away even
  // if it looks unused.
  const char* volatile p = kSourceTimestamp;
  static_cast<void>(p);
}

}  // namespace webrtc
<commit_msg>Update WebRTC code version (2021-01-04T04:02:59).<commit_after>/*
 *  Copyright (c) 2020 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 "call/version.h"

namespace webrtc {

// The timestamp is always in UTC.
const char* const kSourceTimestamp = "WebRTC source stamp 2021-01-04T04:02:59";

void LoadWebRTCVersionInRegister() {
  // Using volatile to instruct the compiler to not optimize `p` away even
  // if it looks unused.
  const char* volatile p = kSourceTimestamp;
  static_cast<void>(p);
}

}  // namespace webrtc
<|endoftext|>


<commit_before><commit_msg>CppCheck cleaning : reduce scope<commit_after><|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"

void
Security::EncodeLargeConstants()
{
#pragma prefast(suppress:6236 6285, "logical-or of constants is by design")
    if (PHASE_OFF(Js::EncodeConstantsPhase, this->func) || CONFIG_ISENABLED(Js::DebugFlag) || !MD_ENCODE_LG_CONSTS)
    {
        return;
    }

    FOREACH_REAL_INSTR_IN_FUNC_EDITING(instr, instrNext, this->func)
    {
        if (!instr->IsRealInstr())
        {
            continue;
        }
        IR::Opnd *dst = instr->GetDst();
        if (dst)
        {
            this->EncodeOpnd(instr, dst);
        }
        IR::Opnd *src1 = instr->GetSrc1();
        if (src1)
        {
            this->EncodeOpnd(instr, src1);

            IR::Opnd *src2 = instr->GetSrc2();
            if (src2)
            {
                this->EncodeOpnd(instr, src2);
            }
        }
    } NEXT_REAL_INSTR_IN_FUNC_EDITING;
}

int
Security::GetNextNOPInsertPoint()
{
    uint frequency = (1 << CONFIG_FLAG(NopFrequency)) - 1;
    return (Math::Rand() & frequency) + 1;
}

void
Security::InsertRandomFunctionPad(IR::Instr * instrBeforeInstr)
{
    if (PHASE_OFF(Js::InsertNOPsPhase, instrBeforeInstr->m_func->GetTopFunc())
        || CONFIG_ISENABLED(Js::DebugFlag) || CONFIG_ISENABLED(Js::BenchmarkFlag))
    {
        return;
    }
    DWORD randomPad = Math::Rand() & ((0 - INSTR_ALIGNMENT) & 0xF);
#ifndef _M_ARM
    if (randomPad == 1)
    {
        InsertSmallNOP(instrBeforeInstr, 1);
        return;
    }
    if (randomPad & 1)
    {
        InsertSmallNOP(instrBeforeInstr, 3);
        randomPad -= 3;
    }
#endif
    Assert((randomPad & 1) == 0);
    while (randomPad >= 4)
    {
        InsertSmallNOP(instrBeforeInstr, 4);
        randomPad -= 4;
    }
    Assert(randomPad == 2 || randomPad == 0);
    if (randomPad == 2)
    {
        InsertSmallNOP(instrBeforeInstr, 2);
    }
}

void
Security::InsertNOPs()
{
    if (PHASE_OFF(Js::InsertNOPsPhase, this->func) || CONFIG_ISENABLED(Js::DebugFlag) || CONFIG_ISENABLED(Js::BenchmarkFlag))
    {
        return;
    }

    int count = 0;
    IR::Instr *instr = this->func->m_headInstr;

    while(true)
    {
        count = this->GetNextNOPInsertPoint();
        while(instr && count--)
        {
            instr = instr->GetNextRealInstr();
        }
        if (instr == nullptr)
        {
            break;
        }
        this->InsertNOPBefore(instr);
    };
}

void
Security::InsertNOPBefore(IR::Instr *instr)
{
    InsertSmallNOP(instr, (Math::Rand() & 0x3) + 1);
}

void
Security::InsertSmallNOP(IR::Instr * instr, DWORD nopSize)
{
#if defined(_M_IX86) || defined(_M_X64)
#ifdef _M_IX86
    if (AutoSystemInfo::Data.SSE2Available())
    {   // on x86 system that has SSE2, encode fast NOPs as x64 does
#endif
        Assert(nopSize >= 1 || nopSize <= 4);
        IR::Instr *nop = IR::Instr::New(Js::OpCode::NOP, instr->m_func);

        // Let the encoder know what the size of the NOP needs to be.
        if (nopSize > 1)
        {
            // 2, 3 or 4 byte NOP.
            IR::IntConstOpnd *nopSizeOpnd = IR::IntConstOpnd::New(nopSize, TyInt8, instr->m_func);
            nop->SetSrc1(nopSizeOpnd);
        }

        instr->InsertBefore(nop);
#ifdef _M_IX86
    }
    else
    {
        IR::Instr *nopInstr = nullptr;
        IR::RegOpnd *regOpnd;
        IR::IndirOpnd *indirOpnd;
        switch (nopSize)
        {
        case 1:
            // nop
            nopInstr = IR::Instr::New(Js::OpCode::NOP, instr->m_func);
            break;
        case 2:
            // mov edi, edi         ; 2 bytes
            regOpnd = IR::RegOpnd::New(nullptr, RegEDI, TyInt32, instr->m_func);
            nopInstr = IR::Instr::New(Js::OpCode::MOV, regOpnd, regOpnd, instr->m_func);
            break;
        case 3:
            // lea ecx, [ecx+00]    ; 3 bytes
            regOpnd = IR::RegOpnd::New(nullptr, RegECX, TyInt32, instr->m_func);
            indirOpnd = IR::IndirOpnd::New(regOpnd, (int32)0, TyInt32, instr->m_func);
            nopInstr = IR::Instr::New(Js::OpCode::LEA, regOpnd, indirOpnd, instr->m_func);
            break;
        case 4:
            // lea esp, [esp+00]    ; 4 bytes
            regOpnd = IR::RegOpnd::New(nullptr, RegESP, TyInt32, instr->m_func);
            indirOpnd = IR::IndirOpnd::New(regOpnd, (int32)0, TyInt32, instr->m_func);
            nopInstr = IR::Instr::New(Js::OpCode::LEA, regOpnd, indirOpnd, instr->m_func);
            break;
        default:
            Assert(false);
            break;
        }
        instr->InsertBefore(nopInstr);
    }
#endif
#elif defined(_M_ARM)
    // Can't insert 3 bytes, must choose between 2 and 4.

    IR::Instr *nopInstr = nullptr;

    switch(nopSize)
    {
    case 1:
    case 2:
        nopInstr = IR::Instr::New(Js::OpCode::NOP, instr->m_func);
        break;
    case 3:
    case 4:
        nopInstr = IR::Instr::New(Js::OpCode::NOP_W, instr->m_func);
        break;
    default:
        Assert(false);
        break;
    }

    instr->InsertBefore(nopInstr);
#else
    AssertMsg(false, "Unimplemented");
#endif
}

bool
Security::DontEncode(IR::Opnd *opnd)
{
    switch (opnd->GetKind())
    {
    case IR::OpndKindIntConst:
    {
        IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();
        return intConstOpnd->m_dontEncode;
    }

    case IR::OpndKindAddr:
    {
        IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();
        return (addrOpnd->m_dontEncode ||
                !addrOpnd->IsVar() ||
                addrOpnd->m_address == nullptr ||
                !Js::TaggedNumber::Is(addrOpnd->m_address));
    }

    case IR::OpndKindHelperCall:
        // Never encode helper call addresses, as these are always internal constants.
        return true;
    }

    return false;
}

void
Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
{
    IR::RegOpnd *newOpnd;
    bool isSrc2 = false;

    if (Security::DontEncode(opnd))
    {
        return;
    }

    switch(opnd->GetKind())
    {
    case IR::OpndKindIntConst:
    {
        IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();

        if (
#if TARGET_64
            (IRType_IsInt64(intConstOpnd->GetType()) && !this->IsLargeConstant(intConstOpnd->GetValue())) ||
#endif
            !this->IsLargeConstant(intConstOpnd->AsInt32()))
        {
            return;
        }

        if (opnd != instr->GetSrc1())
        {
            Assert(opnd == instr->GetSrc2());
            isSrc2 = true;
            instr->UnlinkSrc2();
        }
        else
        {
            instr->UnlinkSrc1();
        }

#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
        intConstOpnd->decodedValue = intConstOpnd->GetValue();
#endif

        intConstOpnd->SetValue(EncodeValue(instr, intConstOpnd, intConstOpnd->GetValue(), &newOpnd));
    }
    break;

    case IR::OpndKindAddr:
    {
        IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();

        // Only encode large constants.  Small ones don't allow control of enough bits
        if (Js::TaggedInt::Is(addrOpnd->m_address) && !this->IsLargeConstant(Js::TaggedInt::ToInt32(addrOpnd->m_address)))
        {
            return;
        }

        if (opnd != instr->GetSrc1())
        {
            Assert(opnd == instr->GetSrc2());
            isSrc2 = true;
            instr->UnlinkSrc2();
        }
        else
        {
            instr->UnlinkSrc1();
        }

        addrOpnd->SetEncodedValue((Js::Var)this->EncodeValue(instr, addrOpnd, (IntConstType)addrOpnd->m_address, &newOpnd), addrOpnd->GetAddrOpndKind());
    }
    break;

    case IR::OpndKindIndir:
    {
        IR::IndirOpnd *indirOpnd = opnd->AsIndirOpnd();

        if (!this->IsLargeConstant(indirOpnd->GetOffset()) || indirOpnd->m_dontEncode)
        {
            return;
        }
        AssertMsg(indirOpnd->GetIndexOpnd() == nullptr, "Code currently doesn't support indir with offset and indexOpnd");

        IR::IntConstOpnd *indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, instr->m_func);
#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
        indexOpnd->decodedValue = indexOpnd->GetValue();
#endif

        indexOpnd->SetValue(EncodeValue(instr, indexOpnd, indexOpnd->GetValue(), &newOpnd));
        indirOpnd->SetOffset(0);
        indirOpnd->SetIndexOpnd(newOpnd);
    }
    return;

    default:
        return;
    }

    IR::Opnd *dst = instr->GetDst();

    if (dst)
    {
#if _M_X64
        // Ensure the left and right operand has the same type (that might not be true for constants on x64)
        newOpnd = (IR::RegOpnd *)newOpnd->UseWithNewType(dst->GetType(), instr->m_func);
#endif
        if (dst->IsRegOpnd())
        {
            IR::RegOpnd *dstRegOpnd = dst->AsRegOpnd();
            StackSym *dstSym = dstRegOpnd->m_sym;

            if (dstSym)
            {
                dstSym->m_isConst = false;
                dstSym->m_isIntConst = false;
                dstSym->m_isInt64Const = false;
                dstSym->m_isTaggableIntConst = false;
                dstSym->m_isFltConst = false;
            }
        }
    }

     LowererMD::ImmedSrcToReg(instr, newOpnd, isSrc2 ? 2 : 1);
}

IntConstType
Security::EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue, IR::RegOpnd **pNewOpnd)
{
    if (opnd->GetType() == TyInt32 || opnd->GetType() == TyInt16 || opnd->GetType() == TyInt8
#if _M_IX86
        || opnd->GetType() == TyVar
#endif
        )
    {
        int32 cookie = (int32)Math::Rand();
        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(TyInt32, instr->m_func), TyInt32, instr->m_func);
        IR::Instr * instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);

        IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, TyInt32, instr->m_func);

#if DBG_DUMP
        cookieOpnd->name = _u("cookie");
#endif

        instrNew = IR::Instr::New(Js::OpCode::Xor_I4, regOpnd, regOpnd, cookieOpnd, instr->m_func);
        instr->InsertBefore(instrNew);

        LowererMD::EmitInt4Instr(instrNew);

        StackSym * stackSym = regOpnd->m_sym;
        Assert(!stackSym->m_isSingleDef);
        Assert(stackSym->m_instrDef == nullptr);
        stackSym->m_isEncodedConstant = true;
        stackSym->constantValue = (int32)constValue;

        *pNewOpnd = regOpnd;

        int32 value = (int32)constValue;
        value = value ^ cookie;
        return value;
    }
    else if (opnd->GetType() == TyUint32 || opnd->GetType() == TyUint16 || opnd->GetType() == TyUint8)
    {
        uint32 cookie = (uint32)Math::Rand();
        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(TyUint32, instr->m_func), TyUint32, instr->m_func);
        IR::Instr * instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);

        IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, TyUint32, instr->m_func);

#if DBG_DUMP
        cookieOpnd->name = _u("cookie");
#endif

        instrNew = IR::Instr::New(Js::OpCode::Xor_I4, regOpnd, regOpnd, cookieOpnd, instr->m_func);
        instr->InsertBefore(instrNew);

        LowererMD::EmitInt4Instr(instrNew);

        StackSym * stackSym = regOpnd->m_sym;
        Assert(!stackSym->m_isSingleDef);
        Assert(stackSym->m_instrDef == nullptr);
        stackSym->m_isEncodedConstant = true;
        stackSym->constantValue = (uint32)constValue;

        *pNewOpnd = regOpnd;

        uint32 value = (uint32)constValue;
        value = value ^ cookie;
        return (IntConstType)value;
    }
    else
    {
#ifdef _M_X64
        return this->EncodeAddress(instr, opnd, constValue, pNewOpnd);
#else
        Assert(false);
        return 0;
#endif
    }
}

#ifdef _M_X64
size_t
Security::EncodeAddress(IR::Instr *instr, IR::Opnd *opnd, size_t value, IR::RegOpnd **pNewOpnd)
{
    IR::Instr   *instrNew = nullptr;
    IR::RegOpnd *regOpnd  = IR::RegOpnd::New(TyMachReg, instr->m_func);

    instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);

    size_t cookie = (size_t)Math::Rand();
    IR::IntConstOpnd *cookieOpnd = IR::IntConstOpnd::New(cookie, TyMachReg, instr->m_func);
    instrNew = IR::Instr::New(Js::OpCode::XOR, regOpnd, regOpnd, cookieOpnd, instr->m_func);
    instr->InsertBefore(instrNew);
    LowererMD::Legalize(instrNew);

    StackSym * stackSym = regOpnd->m_sym;
    Assert(!stackSym->m_isSingleDef);
    Assert(stackSym->m_instrDef == nullptr);
    stackSym->m_isEncodedConstant = true;
    stackSym->constantValue = value;

    *pNewOpnd = regOpnd;
    return value ^ cookie;
}
#endif
<commit_msg>[1.4>2.0] Revert change made when encoding large constant for Wasm bug as it has a big perf impact.<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"

void
Security::EncodeLargeConstants()
{
#pragma prefast(suppress:6236 6285, "logical-or of constants is by design")
    if (PHASE_OFF(Js::EncodeConstantsPhase, this->func) || CONFIG_ISENABLED(Js::DebugFlag) || !MD_ENCODE_LG_CONSTS)
    {
        return;
    }

    FOREACH_REAL_INSTR_IN_FUNC_EDITING(instr, instrNext, this->func)
    {
        if (!instr->IsRealInstr())
        {
            continue;
        }
        IR::Opnd *dst = instr->GetDst();
        if (dst)
        {
            this->EncodeOpnd(instr, dst);
        }
        IR::Opnd *src1 = instr->GetSrc1();
        if (src1)
        {
            this->EncodeOpnd(instr, src1);

            IR::Opnd *src2 = instr->GetSrc2();
            if (src2)
            {
                this->EncodeOpnd(instr, src2);
            }
        }
    } NEXT_REAL_INSTR_IN_FUNC_EDITING;
}

int
Security::GetNextNOPInsertPoint()
{
    uint frequency = (1 << CONFIG_FLAG(NopFrequency)) - 1;
    return (Math::Rand() & frequency) + 1;
}

void
Security::InsertRandomFunctionPad(IR::Instr * instrBeforeInstr)
{
    if (PHASE_OFF(Js::InsertNOPsPhase, instrBeforeInstr->m_func->GetTopFunc())
        || CONFIG_ISENABLED(Js::DebugFlag) || CONFIG_ISENABLED(Js::BenchmarkFlag))
    {
        return;
    }
    DWORD randomPad = Math::Rand() & ((0 - INSTR_ALIGNMENT) & 0xF);
#ifndef _M_ARM
    if (randomPad == 1)
    {
        InsertSmallNOP(instrBeforeInstr, 1);
        return;
    }
    if (randomPad & 1)
    {
        InsertSmallNOP(instrBeforeInstr, 3);
        randomPad -= 3;
    }
#endif
    Assert((randomPad & 1) == 0);
    while (randomPad >= 4)
    {
        InsertSmallNOP(instrBeforeInstr, 4);
        randomPad -= 4;
    }
    Assert(randomPad == 2 || randomPad == 0);
    if (randomPad == 2)
    {
        InsertSmallNOP(instrBeforeInstr, 2);
    }
}

void
Security::InsertNOPs()
{
    if (PHASE_OFF(Js::InsertNOPsPhase, this->func) || CONFIG_ISENABLED(Js::DebugFlag) || CONFIG_ISENABLED(Js::BenchmarkFlag))
    {
        return;
    }

    int count = 0;
    IR::Instr *instr = this->func->m_headInstr;

    while(true)
    {
        count = this->GetNextNOPInsertPoint();
        while(instr && count--)
        {
            instr = instr->GetNextRealInstr();
        }
        if (instr == nullptr)
        {
            break;
        }
        this->InsertNOPBefore(instr);
    };
}

void
Security::InsertNOPBefore(IR::Instr *instr)
{
    InsertSmallNOP(instr, (Math::Rand() & 0x3) + 1);
}

void
Security::InsertSmallNOP(IR::Instr * instr, DWORD nopSize)
{
#if defined(_M_IX86) || defined(_M_X64)
#ifdef _M_IX86
    if (AutoSystemInfo::Data.SSE2Available())
    {   // on x86 system that has SSE2, encode fast NOPs as x64 does
#endif
        Assert(nopSize >= 1 || nopSize <= 4);
        IR::Instr *nop = IR::Instr::New(Js::OpCode::NOP, instr->m_func);

        // Let the encoder know what the size of the NOP needs to be.
        if (nopSize > 1)
        {
            // 2, 3 or 4 byte NOP.
            IR::IntConstOpnd *nopSizeOpnd = IR::IntConstOpnd::New(nopSize, TyInt8, instr->m_func);
            nop->SetSrc1(nopSizeOpnd);
        }

        instr->InsertBefore(nop);
#ifdef _M_IX86
    }
    else
    {
        IR::Instr *nopInstr = nullptr;
        IR::RegOpnd *regOpnd;
        IR::IndirOpnd *indirOpnd;
        switch (nopSize)
        {
        case 1:
            // nop
            nopInstr = IR::Instr::New(Js::OpCode::NOP, instr->m_func);
            break;
        case 2:
            // mov edi, edi         ; 2 bytes
            regOpnd = IR::RegOpnd::New(nullptr, RegEDI, TyInt32, instr->m_func);
            nopInstr = IR::Instr::New(Js::OpCode::MOV, regOpnd, regOpnd, instr->m_func);
            break;
        case 3:
            // lea ecx, [ecx+00]    ; 3 bytes
            regOpnd = IR::RegOpnd::New(nullptr, RegECX, TyInt32, instr->m_func);
            indirOpnd = IR::IndirOpnd::New(regOpnd, (int32)0, TyInt32, instr->m_func);
            nopInstr = IR::Instr::New(Js::OpCode::LEA, regOpnd, indirOpnd, instr->m_func);
            break;
        case 4:
            // lea esp, [esp+00]    ; 4 bytes
            regOpnd = IR::RegOpnd::New(nullptr, RegESP, TyInt32, instr->m_func);
            indirOpnd = IR::IndirOpnd::New(regOpnd, (int32)0, TyInt32, instr->m_func);
            nopInstr = IR::Instr::New(Js::OpCode::LEA, regOpnd, indirOpnd, instr->m_func);
            break;
        default:
            Assert(false);
            break;
        }
        instr->InsertBefore(nopInstr);
    }
#endif
#elif defined(_M_ARM)
    // Can't insert 3 bytes, must choose between 2 and 4.

    IR::Instr *nopInstr = nullptr;

    switch(nopSize)
    {
    case 1:
    case 2:
        nopInstr = IR::Instr::New(Js::OpCode::NOP, instr->m_func);
        break;
    case 3:
    case 4:
        nopInstr = IR::Instr::New(Js::OpCode::NOP_W, instr->m_func);
        break;
    default:
        Assert(false);
        break;
    }

    instr->InsertBefore(nopInstr);
#else
    AssertMsg(false, "Unimplemented");
#endif
}

bool
Security::DontEncode(IR::Opnd *opnd)
{
    switch (opnd->GetKind())
    {
    case IR::OpndKindIntConst:
    {
        IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();
        return intConstOpnd->m_dontEncode;
    }

    case IR::OpndKindAddr:
    {
        IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();
        return (addrOpnd->m_dontEncode ||
                !addrOpnd->IsVar() ||
                addrOpnd->m_address == nullptr ||
                !Js::TaggedNumber::Is(addrOpnd->m_address));
    }

    case IR::OpndKindHelperCall:
        // Never encode helper call addresses, as these are always internal constants.
        return true;
    }

    return false;
}

void
Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
{
    IR::RegOpnd *newOpnd;
    bool isSrc2 = false;

    if (Security::DontEncode(opnd))
    {
        return;
    }

    switch(opnd->GetKind())
    {
    case IR::OpndKindIntConst:
    {
        IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();

        if (
#if TARGET_64
            IRType_IsInt64(intConstOpnd->GetType()) ? !this->IsLargeConstant(intConstOpnd->GetValue()) :
#endif
            !this->IsLargeConstant(intConstOpnd->AsInt32()))
        {
            return;
        }

        if (opnd != instr->GetSrc1())
        {
            Assert(opnd == instr->GetSrc2());
            isSrc2 = true;
            instr->UnlinkSrc2();
        }
        else
        {
            instr->UnlinkSrc1();
        }

#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
        intConstOpnd->decodedValue = intConstOpnd->GetValue();
#endif

        intConstOpnd->SetValue(EncodeValue(instr, intConstOpnd, intConstOpnd->GetValue(), &newOpnd));
    }
    break;

    case IR::OpndKindAddr:
    {
        IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();

        // Only encode large constants.  Small ones don't allow control of enough bits
        if (Js::TaggedInt::Is(addrOpnd->m_address) && !this->IsLargeConstant(Js::TaggedInt::ToInt32(addrOpnd->m_address)))
        {
            return;
        }

        if (opnd != instr->GetSrc1())
        {
            Assert(opnd == instr->GetSrc2());
            isSrc2 = true;
            instr->UnlinkSrc2();
        }
        else
        {
            instr->UnlinkSrc1();
        }

        addrOpnd->SetEncodedValue((Js::Var)this->EncodeValue(instr, addrOpnd, (IntConstType)addrOpnd->m_address, &newOpnd), addrOpnd->GetAddrOpndKind());
    }
    break;

    case IR::OpndKindIndir:
    {
        IR::IndirOpnd *indirOpnd = opnd->AsIndirOpnd();

        if (!this->IsLargeConstant(indirOpnd->GetOffset()) || indirOpnd->m_dontEncode)
        {
            return;
        }
        AssertMsg(indirOpnd->GetIndexOpnd() == nullptr, "Code currently doesn't support indir with offset and indexOpnd");

        IR::IntConstOpnd *indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, instr->m_func);
#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
        indexOpnd->decodedValue = indexOpnd->GetValue();
#endif

        indexOpnd->SetValue(EncodeValue(instr, indexOpnd, indexOpnd->GetValue(), &newOpnd));
        indirOpnd->SetOffset(0);
        indirOpnd->SetIndexOpnd(newOpnd);
    }
    return;

    default:
        return;
    }

    IR::Opnd *dst = instr->GetDst();

    if (dst)
    {
#if _M_X64
        // Ensure the left and right operand has the same type (that might not be true for constants on x64)
        newOpnd = (IR::RegOpnd *)newOpnd->UseWithNewType(dst->GetType(), instr->m_func);
#endif
        if (dst->IsRegOpnd())
        {
            IR::RegOpnd *dstRegOpnd = dst->AsRegOpnd();
            StackSym *dstSym = dstRegOpnd->m_sym;

            if (dstSym)
            {
                dstSym->m_isConst = false;
                dstSym->m_isIntConst = false;
                dstSym->m_isInt64Const = false;
                dstSym->m_isTaggableIntConst = false;
                dstSym->m_isFltConst = false;
            }
        }
    }

     LowererMD::ImmedSrcToReg(instr, newOpnd, isSrc2 ? 2 : 1);
}

IntConstType
Security::EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue, IR::RegOpnd **pNewOpnd)
{
    if (opnd->GetType() == TyInt32 || opnd->GetType() == TyInt16 || opnd->GetType() == TyInt8
#if _M_IX86
        || opnd->GetType() == TyVar
#endif
        )
    {
        int32 cookie = (int32)Math::Rand();
        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(TyInt32, instr->m_func), TyInt32, instr->m_func);
        IR::Instr * instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);

        IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, TyInt32, instr->m_func);

#if DBG_DUMP
        cookieOpnd->name = _u("cookie");
#endif

        instrNew = IR::Instr::New(Js::OpCode::Xor_I4, regOpnd, regOpnd, cookieOpnd, instr->m_func);
        instr->InsertBefore(instrNew);

        LowererMD::EmitInt4Instr(instrNew);

        StackSym * stackSym = regOpnd->m_sym;
        Assert(!stackSym->m_isSingleDef);
        Assert(stackSym->m_instrDef == nullptr);
        stackSym->m_isEncodedConstant = true;
        stackSym->constantValue = (int32)constValue;

        *pNewOpnd = regOpnd;

        int32 value = (int32)constValue;
        value = value ^ cookie;
        return value;
    }
    else if (opnd->GetType() == TyUint32 || opnd->GetType() == TyUint16 || opnd->GetType() == TyUint8)
    {
        uint32 cookie = (uint32)Math::Rand();
        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(TyUint32, instr->m_func), TyUint32, instr->m_func);
        IR::Instr * instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);

        IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, TyUint32, instr->m_func);

#if DBG_DUMP
        cookieOpnd->name = _u("cookie");
#endif

        instrNew = IR::Instr::New(Js::OpCode::Xor_I4, regOpnd, regOpnd, cookieOpnd, instr->m_func);
        instr->InsertBefore(instrNew);

        LowererMD::EmitInt4Instr(instrNew);

        StackSym * stackSym = regOpnd->m_sym;
        Assert(!stackSym->m_isSingleDef);
        Assert(stackSym->m_instrDef == nullptr);
        stackSym->m_isEncodedConstant = true;
        stackSym->constantValue = (uint32)constValue;

        *pNewOpnd = regOpnd;

        uint32 value = (uint32)constValue;
        value = value ^ cookie;
        return (IntConstType)value;
    }
    else
    {
#ifdef _M_X64
        return this->EncodeAddress(instr, opnd, constValue, pNewOpnd);
#else
        Assert(false);
        return 0;
#endif
    }
}

#ifdef _M_X64
size_t
Security::EncodeAddress(IR::Instr *instr, IR::Opnd *opnd, size_t value, IR::RegOpnd **pNewOpnd)
{
    IR::Instr   *instrNew = nullptr;
    IR::RegOpnd *regOpnd  = IR::RegOpnd::New(TyMachReg, instr->m_func);

    instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);

    size_t cookie = (size_t)Math::Rand();
    IR::IntConstOpnd *cookieOpnd = IR::IntConstOpnd::New(cookie, TyMachReg, instr->m_func);
    instrNew = IR::Instr::New(Js::OpCode::XOR, regOpnd, regOpnd, cookieOpnd, instr->m_func);
    instr->InsertBefore(instrNew);
    LowererMD::Legalize(instrNew);

    StackSym * stackSym = regOpnd->m_sym;
    Assert(!stackSym->m_isSingleDef);
    Assert(stackSym->m_instrDef == nullptr);
    stackSym->m_isEncodedConstant = true;
    stackSym->constantValue = value;

    *pNewOpnd = regOpnd;
    return value ^ cookie;
}
#endif
<|endoftext|>