<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "oglwindow.hxx"
#include <cppuhelper/supportsservice.hxx>

using namespace com::sun::star;
using namespace libgltf;

namespace avmedia { namespace ogl {

OGLWindow::OGLWindow( glTFHandle& rHandle, OpenGLContext& rContext, Window& rEventHandlerParent )
    : m_rHandle( rHandle )
    , m_rContext( rContext )
    , m_rEventHandler( rEventHandlerParent )
    , m_bVisible ( false )
    , m_aLastMousePos(Point(0,0))
    , m_bIsOrbitMode( false )
{
}

OGLWindow::~OGLWindow()
{
    dispose();
}

void SAL_CALL OGLWindow::update() throw (css::uno::RuntimeException, std::exception)
{
    m_rContext.makeCurrent();
    int nRet = gltf_prepare_renderer(&m_rHandle);
    if( nRet != 0 )
    {
        SAL_WARN("avmedia.opengl", "Error occured while preparing for rendering! Error code: " << nRet);
        return;
    }
    gltf_renderer(&m_rHandle);
    gltf_complete_renderer(&m_rHandle);
    m_rContext.swapBuffers();
}

sal_Bool SAL_CALL OGLWindow::setZoomLevel( css::media::ZoomLevel /*eZoomLevel*/ ) throw (css::uno::RuntimeException, std::exception)
{
    return false;
}

css::media::ZoomLevel SAL_CALL OGLWindow::getZoomLevel() throw (css::uno::RuntimeException, std::exception)
{
    return media::ZoomLevel_ORIGINAL;
}

void SAL_CALL OGLWindow::setPointerType( sal_Int32 ) throw (css::uno::RuntimeException, std::exception)
{
}

OUString SAL_CALL OGLWindow::getImplementationName() throw (css::uno::RuntimeException, std::exception)
{
    return OUString("com.sun.star.comp.avmedia.Window_OpenGL");
}

sal_Bool SAL_CALL OGLWindow::supportsService( const OUString& rServiceName ) throw (css::uno::RuntimeException, std::exception)
{
    return cppu::supportsService(this, rServiceName);
}

uno::Sequence< OUString > SAL_CALL OGLWindow::getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception)
{
    uno::Sequence< OUString > aRet(1);
    aRet[0] = OUString("com.sun.star.media.Window_OpenGL");
    return aRet;
}

void SAL_CALL OGLWindow::dispose() throw (uno::RuntimeException, std::exception)
{
    assert(m_rEventHandler.GetParent());
    m_rEventHandler.GetParent()->RemoveEventListener( LINK(this, OGLWindow, FocusGrabber));
    m_rEventHandler.RemoveEventListener( LINK(this, OGLWindow, CameraHandler));
}

void SAL_CALL OGLWindow::addEventListener( const uno::Reference< lang::XEventListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeEventListener( const uno::Reference< lang::XEventListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::setPosSize( sal_Int32 nX, sal_Int32 nY, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int16 /*nFlags*/ )
    throw (uno::RuntimeException, std::exception)
{
    if( m_rHandle.viewport.x != nX || m_rHandle.viewport.x != nY ||
        m_rHandle.viewport.width != nWidth || m_rHandle.viewport.height != nHeight )
    {
        m_rContext.setWinSize(Size(nWidth,nHeight));
        m_rHandle.viewport.x = nX;
        m_rHandle.viewport.y = nY;
        m_rHandle.viewport.width = nWidth;
        m_rHandle.viewport.height = nHeight;
    }
}

awt::Rectangle SAL_CALL OGLWindow::getPosSize()
    throw (uno::RuntimeException, std::exception)
{
    return awt::Rectangle(m_rHandle.viewport.x, m_rHandle.viewport.y,
                          m_rHandle.viewport.width, m_rHandle.viewport.height);
}

void SAL_CALL OGLWindow::setVisible( sal_Bool bSet )
    throw (uno::RuntimeException, std::exception)
{
    assert(m_rEventHandler.GetParent());
    if( bSet && !m_bVisible )
    {
        m_rEventHandler.GetParent()->AddEventListener( LINK(this, OGLWindow, FocusGrabber));
        m_rEventHandler.AddEventListener( LINK(this, OGLWindow, CameraHandler));
        m_rEventHandler.GrabFocus();
    }
    else if( !bSet )
    {
        m_rEventHandler.GetParent()->RemoveEventListener( LINK(this, OGLWindow, FocusGrabber));
        m_rEventHandler.RemoveEventListener( LINK(this, OGLWindow, CameraHandler));
    }
    m_bVisible = bSet;
}

void SAL_CALL OGLWindow::setEnable( sal_Bool )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::setFocus()
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addWindowListener( const uno::Reference< awt::XWindowListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeWindowListener( const uno::Reference< awt::XWindowListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addFocusListener( const uno::Reference< awt::XFocusListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeFocusListener( const uno::Reference< awt::XFocusListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addKeyListener( const uno::Reference< awt::XKeyListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeKeyListener( const uno::Reference< awt::XKeyListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addMouseListener( const uno::Reference< awt::XMouseListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeMouseListener( const uno::Reference< awt::XMouseListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addPaintListener( const uno::Reference< awt::XPaintListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removePaintListener( const uno::Reference< awt::XPaintListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

IMPL_LINK(OGLWindow, FocusGrabber, VclWindowEvent*, pEvent)
{
    if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEMOVE )
    {
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt)
        {
            const Point& rMousePos = pMouseEvt->GetPosPixel();
            const Rectangle aWinRect(m_rEventHandler.GetPosPixel(),m_rEventHandler.GetSizePixel());
            // Grab focus to the OpenGL window when mouse pointer is over it
            if( aWinRect.IsInside(rMousePos) )
            {
                if ( !m_rEventHandler.HasFocus() )
                {
                    m_rEventHandler.GrabFocus();
                }
            }
            // Move focus to the document when mouse is not over the OpenGL window
            else if ( m_rEventHandler.HasFocus() )
            {
                m_rEventHandler.GrabFocusToDocument();
            }
        }
    }

    return 0;
}

IMPL_LINK(OGLWindow, CameraHandler, VclWindowEvent*, pEvent)
{
    if( pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT )
    {
        KeyEvent* pKeyEvt = (KeyEvent*)pEvent->GetData();
        if(pKeyEvt)
        {
            const sal_uInt16 nCode = pKeyEvt->GetKeyCode().GetCode();
            if (nCode == KEY_Q || nCode == KEY_E ||
                nCode == KEY_A || nCode == KEY_D ||
                nCode == KEY_W || nCode == KEY_S )
            {
                // Calculate movement
                glm::vec3 vMoveBy;
                {
                    glm::vec3 vEye;
                    glm::vec3 vView;
                    glm::vec3 vUp;
                    gltf_get_camera_pos(&m_rHandle, &vEye,&vView,&vUp);
                    float fModelSize =(float)gltf_get_model_size(&m_rHandle);

                    glm::vec3 vMove = vView-vEye;
                    vMove = glm::normalize(vMove);
                    vMove *= 25.0f;
                    glm::vec3 vStrafe = glm::cross(vMove, vUp);
                    vStrafe = glm::normalize(vStrafe);
                    vStrafe *= 25.0f;
                    glm::vec3 vMup = vUp * 25.0f;

                    if( !m_bIsOrbitMode )
                    {
                        if(nCode == KEY_E)vMoveBy += vMup*(0.0005f*fModelSize);
                        if(nCode == KEY_Q)vMoveBy -= vMup*(0.0005f*fModelSize);
                        if(nCode == KEY_W)vMoveBy += vMove*(0.0005f*fModelSize);
                        if(nCode == KEY_S)vMoveBy -= vMove*(0.0005f*fModelSize);
                        if(nCode == KEY_A)vMoveBy -= vStrafe*(0.0005f*fModelSize);
                        if(nCode == KEY_D)vMoveBy += vStrafe*(0.0005f*fModelSize);
                    }
                    else
                    {
                        bool bZoomIn = false;
                        bool bZoomOut = false;
                        if(nCode == KEY_E)
                        {
                            vMoveBy += vMove*(0.0005f*fModelSize);
                            bZoomIn = true;
                        }
                        if(nCode == KEY_Q)
                        {
                            vMoveBy -= vMove*(0.0005f*fModelSize);
                            bZoomOut = true;
                        }

                        // Limit zooming in orbit mode
                        float fCameraDistFromModelGlobe = glm::length(vEye + vMoveBy - vView) - fModelSize / 2.0f;
                        if ((fCameraDistFromModelGlobe < 0.5 * fModelSize && bZoomIn ) ||
                            (fCameraDistFromModelGlobe > 2 * fModelSize && bZoomOut ))
                        {
                            vMoveBy = glm::vec3(0.0);
                        }
                    }
                }
                gltf_renderer_move_camera(&m_rHandle, vMoveBy.x, vMoveBy.y, vMoveBy.z, 0.0);

                if( m_bIsOrbitMode )
                {
                    long nDeltaX = 0;
                    long nDeltaY = 0;
                    if (nCode == KEY_W)
                    {
                        nDeltaY -= 1;
                    }
                    if (nCode == KEY_S)
                    {
                        nDeltaY += 1;
                    }
                    if (nCode == KEY_A)
                    {
                        nDeltaX -= 1;
                    }
                    if (nCode == KEY_D)
                    {
                        nDeltaX += 1;
                    }
                    float fSensitivity = 50.0;
                    gltf_renderer_rotate_model(&m_rHandle, nDeltaX*fSensitivity, nDeltaY*fSensitivity, 0.0);
                }
            }
            else if(nCode == KEY_M)
            {
                if(m_bIsOrbitMode)
                {
                    gltf_orbit_mode_stop(&m_rHandle);
                    m_bIsOrbitMode = false;
                }
                else
                {
                    gltf_orbit_mode_start(&m_rHandle);
                    m_bIsOrbitMode = true;
                }
            }
            else if(nCode == KEY_F)
            {
                gltf_render_FPS_enable(&m_rHandle);
            }
        }
    }
    else if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEBUTTONDOWN )
    {
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt && pMouseEvt->IsLeft() && pMouseEvt->GetClicks() == 1)
        {
            m_aLastMousePos = pMouseEvt->GetPosPixel();
        }
    }
    else if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEMOVE )
    {
        if ( !m_rEventHandler.HasFocus() )
        {
            m_rEventHandler.GrabFocus();
        }
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt && pMouseEvt->IsLeft() && m_aLastMousePos != Point(0,0))
        {
            const Point& aCurPos = pMouseEvt->GetPosPixel();
            float fSensitivity = std::min(m_rHandle.viewport.width, m_rHandle.viewport.height);
            if (fSensitivity == 0.0)
                fSensitivity = 1.0;
            else
                fSensitivity = 540.0 / fSensitivity;

            long nDeltaX = m_aLastMousePos.X()-aCurPos.X();
            long nDeltaY = m_aLastMousePos.Y()-aCurPos.Y();
            if( m_bIsOrbitMode )
            {
                fSensitivity *= 5;
                gltf_renderer_rotate_model(&m_rHandle, (float)nDeltaX*fSensitivity, (float)nDeltaY*fSensitivity, 0.0);
            }
            else
            {
                // Filter out too small deltas to avoid rewrite rotation parameter with 0
                // before rotation is done
                if( nDeltaX != 0 || nDeltaY != 0 )
                    gltf_renderer_rotate_camera(&m_rHandle, (float)nDeltaX*fSensitivity, (float)nDeltaY*fSensitivity, 0.0);
            }
            m_aLastMousePos = aCurPos;
        }
    }
    else if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEBUTTONUP )
    {
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt && pMouseEvt->IsLeft() && pMouseEvt->GetClicks() == 1)
        {
            m_aLastMousePos = Point(0,0);
        }
    }
    return 0;
}

} // namespace ogl
} // namespace avmedia

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#1233484 Division or modulo by float zero<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "oglwindow.hxx"
#include <cppuhelper/supportsservice.hxx>

using namespace com::sun::star;
using namespace libgltf;

namespace avmedia { namespace ogl {

OGLWindow::OGLWindow( glTFHandle& rHandle, OpenGLContext& rContext, Window& rEventHandlerParent )
    : m_rHandle( rHandle )
    , m_rContext( rContext )
    , m_rEventHandler( rEventHandlerParent )
    , m_bVisible ( false )
    , m_aLastMousePos(Point(0,0))
    , m_bIsOrbitMode( false )
{
}

OGLWindow::~OGLWindow()
{
    dispose();
}

void SAL_CALL OGLWindow::update() throw (css::uno::RuntimeException, std::exception)
{
    m_rContext.makeCurrent();
    int nRet = gltf_prepare_renderer(&m_rHandle);
    if( nRet != 0 )
    {
        SAL_WARN("avmedia.opengl", "Error occured while preparing for rendering! Error code: " << nRet);
        return;
    }
    gltf_renderer(&m_rHandle);
    gltf_complete_renderer(&m_rHandle);
    m_rContext.swapBuffers();
}

sal_Bool SAL_CALL OGLWindow::setZoomLevel( css::media::ZoomLevel /*eZoomLevel*/ ) throw (css::uno::RuntimeException, std::exception)
{
    return false;
}

css::media::ZoomLevel SAL_CALL OGLWindow::getZoomLevel() throw (css::uno::RuntimeException, std::exception)
{
    return media::ZoomLevel_ORIGINAL;
}

void SAL_CALL OGLWindow::setPointerType( sal_Int32 ) throw (css::uno::RuntimeException, std::exception)
{
}

OUString SAL_CALL OGLWindow::getImplementationName() throw (css::uno::RuntimeException, std::exception)
{
    return OUString("com.sun.star.comp.avmedia.Window_OpenGL");
}

sal_Bool SAL_CALL OGLWindow::supportsService( const OUString& rServiceName ) throw (css::uno::RuntimeException, std::exception)
{
    return cppu::supportsService(this, rServiceName);
}

uno::Sequence< OUString > SAL_CALL OGLWindow::getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception)
{
    uno::Sequence< OUString > aRet(1);
    aRet[0] = OUString("com.sun.star.media.Window_OpenGL");
    return aRet;
}

void SAL_CALL OGLWindow::dispose() throw (uno::RuntimeException, std::exception)
{
    assert(m_rEventHandler.GetParent());
    m_rEventHandler.GetParent()->RemoveEventListener( LINK(this, OGLWindow, FocusGrabber));
    m_rEventHandler.RemoveEventListener( LINK(this, OGLWindow, CameraHandler));
}

void SAL_CALL OGLWindow::addEventListener( const uno::Reference< lang::XEventListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeEventListener( const uno::Reference< lang::XEventListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::setPosSize( sal_Int32 nX, sal_Int32 nY, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int16 /*nFlags*/ )
    throw (uno::RuntimeException, std::exception)
{
    if( m_rHandle.viewport.x != nX || m_rHandle.viewport.x != nY ||
        m_rHandle.viewport.width != nWidth || m_rHandle.viewport.height != nHeight )
    {
        m_rContext.setWinSize(Size(nWidth,nHeight));
        m_rHandle.viewport.x = nX;
        m_rHandle.viewport.y = nY;
        m_rHandle.viewport.width = nWidth;
        m_rHandle.viewport.height = nHeight;
    }
}

awt::Rectangle SAL_CALL OGLWindow::getPosSize()
    throw (uno::RuntimeException, std::exception)
{
    return awt::Rectangle(m_rHandle.viewport.x, m_rHandle.viewport.y,
                          m_rHandle.viewport.width, m_rHandle.viewport.height);
}

void SAL_CALL OGLWindow::setVisible( sal_Bool bSet )
    throw (uno::RuntimeException, std::exception)
{
    assert(m_rEventHandler.GetParent());
    if( bSet && !m_bVisible )
    {
        m_rEventHandler.GetParent()->AddEventListener( LINK(this, OGLWindow, FocusGrabber));
        m_rEventHandler.AddEventListener( LINK(this, OGLWindow, CameraHandler));
        m_rEventHandler.GrabFocus();
    }
    else if( !bSet )
    {
        m_rEventHandler.GetParent()->RemoveEventListener( LINK(this, OGLWindow, FocusGrabber));
        m_rEventHandler.RemoveEventListener( LINK(this, OGLWindow, CameraHandler));
    }
    m_bVisible = bSet;
}

void SAL_CALL OGLWindow::setEnable( sal_Bool )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::setFocus()
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addWindowListener( const uno::Reference< awt::XWindowListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeWindowListener( const uno::Reference< awt::XWindowListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addFocusListener( const uno::Reference< awt::XFocusListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeFocusListener( const uno::Reference< awt::XFocusListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addKeyListener( const uno::Reference< awt::XKeyListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeKeyListener( const uno::Reference< awt::XKeyListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addMouseListener( const uno::Reference< awt::XMouseListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeMouseListener( const uno::Reference< awt::XMouseListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removeMouseMotionListener( const uno::Reference< awt::XMouseMotionListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::addPaintListener( const uno::Reference< awt::XPaintListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

void SAL_CALL OGLWindow::removePaintListener( const uno::Reference< awt::XPaintListener >& )
    throw (uno::RuntimeException, std::exception)
{
}

IMPL_LINK(OGLWindow, FocusGrabber, VclWindowEvent*, pEvent)
{
    if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEMOVE )
    {
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt)
        {
            const Point& rMousePos = pMouseEvt->GetPosPixel();
            const Rectangle aWinRect(m_rEventHandler.GetPosPixel(),m_rEventHandler.GetSizePixel());
            // Grab focus to the OpenGL window when mouse pointer is over it
            if( aWinRect.IsInside(rMousePos) )
            {
                if ( !m_rEventHandler.HasFocus() )
                {
                    m_rEventHandler.GrabFocus();
                }
            }
            // Move focus to the document when mouse is not over the OpenGL window
            else if ( m_rEventHandler.HasFocus() )
            {
                m_rEventHandler.GrabFocusToDocument();
            }
        }
    }

    return 0;
}

IMPL_LINK(OGLWindow, CameraHandler, VclWindowEvent*, pEvent)
{
    if( pEvent->GetId() == VCLEVENT_WINDOW_KEYINPUT )
    {
        KeyEvent* pKeyEvt = (KeyEvent*)pEvent->GetData();
        if(pKeyEvt)
        {
            const sal_uInt16 nCode = pKeyEvt->GetKeyCode().GetCode();
            if (nCode == KEY_Q || nCode == KEY_E ||
                nCode == KEY_A || nCode == KEY_D ||
                nCode == KEY_W || nCode == KEY_S )
            {
                // Calculate movement
                glm::vec3 vMoveBy;
                {
                    glm::vec3 vEye;
                    glm::vec3 vView;
                    glm::vec3 vUp;
                    gltf_get_camera_pos(&m_rHandle, &vEye,&vView,&vUp);
                    float fModelSize =(float)gltf_get_model_size(&m_rHandle);

                    glm::vec3 vMove = vView-vEye;
                    vMove = glm::normalize(vMove);
                    vMove *= 25.0f;
                    glm::vec3 vStrafe = glm::cross(vMove, vUp);
                    vStrafe = glm::normalize(vStrafe);
                    vStrafe *= 25.0f;
                    glm::vec3 vMup = vUp * 25.0f;

                    if( !m_bIsOrbitMode )
                    {
                        if(nCode == KEY_E)vMoveBy += vMup*(0.0005f*fModelSize);
                        if(nCode == KEY_Q)vMoveBy -= vMup*(0.0005f*fModelSize);
                        if(nCode == KEY_W)vMoveBy += vMove*(0.0005f*fModelSize);
                        if(nCode == KEY_S)vMoveBy -= vMove*(0.0005f*fModelSize);
                        if(nCode == KEY_A)vMoveBy -= vStrafe*(0.0005f*fModelSize);
                        if(nCode == KEY_D)vMoveBy += vStrafe*(0.0005f*fModelSize);
                    }
                    else
                    {
                        bool bZoomIn = false;
                        bool bZoomOut = false;
                        if(nCode == KEY_E)
                        {
                            vMoveBy += vMove*(0.0005f*fModelSize);
                            bZoomIn = true;
                        }
                        if(nCode == KEY_Q)
                        {
                            vMoveBy -= vMove*(0.0005f*fModelSize);
                            bZoomOut = true;
                        }

                        // Limit zooming in orbit mode
                        float fCameraDistFromModelGlobe = glm::length(vEye + vMoveBy - vView) - fModelSize / 2.0f;
                        if ((fCameraDistFromModelGlobe < 0.5 * fModelSize && bZoomIn ) ||
                            (fCameraDistFromModelGlobe > 2 * fModelSize && bZoomOut ))
                        {
                            vMoveBy = glm::vec3(0.0);
                        }
                    }
                }
                gltf_renderer_move_camera(&m_rHandle, vMoveBy.x, vMoveBy.y, vMoveBy.z, 0.0001);

                if( m_bIsOrbitMode )
                {
                    long nDeltaX = 0;
                    long nDeltaY = 0;
                    if (nCode == KEY_W)
                    {
                        nDeltaY -= 1;
                    }
                    if (nCode == KEY_S)
                    {
                        nDeltaY += 1;
                    }
                    if (nCode == KEY_A)
                    {
                        nDeltaX -= 1;
                    }
                    if (nCode == KEY_D)
                    {
                        nDeltaX += 1;
                    }
                    float fSensitivity = 50.0;
                    gltf_renderer_rotate_model(&m_rHandle, nDeltaX*fSensitivity, nDeltaY*fSensitivity, 0.0);
                }
            }
            else if(nCode == KEY_M)
            {
                if(m_bIsOrbitMode)
                {
                    gltf_orbit_mode_stop(&m_rHandle);
                    m_bIsOrbitMode = false;
                }
                else
                {
                    gltf_orbit_mode_start(&m_rHandle);
                    m_bIsOrbitMode = true;
                }
            }
            else if(nCode == KEY_F)
            {
                gltf_render_FPS_enable(&m_rHandle);
            }
        }
    }
    else if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEBUTTONDOWN )
    {
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt && pMouseEvt->IsLeft() && pMouseEvt->GetClicks() == 1)
        {
            m_aLastMousePos = pMouseEvt->GetPosPixel();
        }
    }
    else if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEMOVE )
    {
        if ( !m_rEventHandler.HasFocus() )
        {
            m_rEventHandler.GrabFocus();
        }
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt && pMouseEvt->IsLeft() && m_aLastMousePos != Point(0,0))
        {
            const Point& aCurPos = pMouseEvt->GetPosPixel();
            float fSensitivity = std::min(m_rHandle.viewport.width, m_rHandle.viewport.height);
            if (fSensitivity == 0.0)
                fSensitivity = 1.0;
            else
                fSensitivity = 540.0 / fSensitivity;

            long nDeltaX = m_aLastMousePos.X()-aCurPos.X();
            long nDeltaY = m_aLastMousePos.Y()-aCurPos.Y();
            if( m_bIsOrbitMode )
            {
                fSensitivity *= 5;
                gltf_renderer_rotate_model(&m_rHandle, (float)nDeltaX*fSensitivity, (float)nDeltaY*fSensitivity, 0.0);
            }
            else
            {
                // Filter out too small deltas to avoid rewrite rotation parameter with 0
                // before rotation is done
                if( nDeltaX != 0 || nDeltaY != 0 )
                    gltf_renderer_rotate_camera(&m_rHandle, (float)nDeltaX*fSensitivity, (float)nDeltaY*fSensitivity, 0.0);
            }
            m_aLastMousePos = aCurPos;
        }
    }
    else if( pEvent->GetId() == VCLEVENT_WINDOW_MOUSEBUTTONUP )
    {
        MouseEvent* pMouseEvt = (MouseEvent*)pEvent->GetData();
        if(pMouseEvt && pMouseEvt->IsLeft() && pMouseEvt->GetClicks() == 1)
        {
            m_aLastMousePos = Point(0,0);
        }
    }
    return 0;
}

} // namespace ogl
} // namespace avmedia

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2015 Barry E. Moore II

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "gaussiancube.h"

#include <avogadro/core/molecule.h>
#include <avogadro/core/utilities.h>
#include <avogadro/core/cube.h>

#include <iostream>

namespace Avogadro {
namespace QuantumIO {

GaussianCube::GaussianCube()
{
}

GaussianCube::~GaussianCube()
{
}

std::vector<std::string> GaussianCube::fileExtensions() const
{
  std::vector<std::string> extensions;
  extensions.push_back("cube");
  return extensions;
}

std::vector<std::string> GaussianCube::mimeTypes() const
{
  return std::vector<std::string>();
}

bool GaussianCube::read(std::istream &in, Core::Molecule &molecule)
{
  // Variables we will need
  std::string line;
  std::vector<std::string> list;

  int nAtoms;
  Vector3 min;
  Vector3 spacing;
  Vector3i dim;

  // Gaussian Cube format is very specific

  // Read and set name
  getline(in, line);
  std::string cubeName = line;

  // Read and skip field title (we may be able to use this to setCubeType in the future)
  getline(in, line);

  // Next line contains nAtoms and m_min
  in >> nAtoms;
  for (unsigned int i = 0; i < 3; ++i)
    in >> min(i);
  getline(in, line); //capture newline before continuing

  // Next 3 lines contains spacing and dim
  for (unsigned int i = 0; i < 3; ++i) {
    getline(in, line);
    line = Core::trimmed(line);
    list = Core::split(line, ' ');
    dim(i) = Core::lexicalCast<int>(list[0]);
    spacing(i) = Core::lexicalCast<double>(list[i + 1]);
  }

  // Geometry block
  Vector3 pos;
  for (unsigned int i = 0; i < abs(nAtoms); ++i) {
    getline(in, line);
    line = Core::trimmed(line);
    list = Core::split(line, ' ');
    short int atomNum = Core::lexicalCast<short int>(list[0]);
    Core::Atom a = molecule.addAtom(static_cast<unsigned char>(atomNum));
    for (unsigned int j = 2; j < 5; ++j)
      pos(j - 2) = Core::lexicalCast<double>(list[j]);
    pos = pos * BOHR_TO_ANGSTROM;
    a.setPosition3d(pos);
  }

  // If the nAtoms were negative there is another line before
  // the data which is necessary, maybe contain 1 or more cubes
  unsigned int nCubes = 1;
  if (nAtoms < 0) {
    in >> nCubes;
    std::vector<unsigned int> moList(nCubes);
    for (unsigned int i = 0; i < nCubes; ++i)
      in >> moList[i];
    // clear buffer
    getline(in, line);
  }

  // Render molecule
  molecule.perceiveBondsSimple();

  // Cube block, set limits and populate data
  // min and spacing are in bohr units, convert to ANGSTROM
  for (unsigned int j = 0; j < 3; ++j) {
    min[j] *= BOHR_TO_ANGSTROM;
    spacing[j] *= BOHR_TO_ANGSTROM;
  }

  for (unsigned int i = 0; i < nCubes; ++i){
    // Get a cube object from molecule
    Core::Cube *cube = molecule.addCube();

    cube->setLimits(min, dim, spacing);
    std::vector<double> values;
    // push_back is slow for this, resize vector first
    values.resize(dim(0) * dim(1) * dim(2));
    for (unsigned int j = 0; j < values.size(); ++j)
      in >> values[j];
    // clear buffer, if more than one cube
    getline(in, line);
    cube->setData(values);
  }

  return true;
}

bool GaussianCube::write(std::ostream &out, const Core::Molecule &molecule)
{
    // Not implemented yet
    return false;
}

} // End QuantumIO namespace
} // End Avogadro namespace
<commit_msg>Minor fix to gaussian cube reader<commit_after>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2015 Barry E. Moore II

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "gaussiancube.h"

#include <avogadro/core/molecule.h>
#include <avogadro/core/utilities.h>
#include <avogadro/core/cube.h>

#include <iostream>

namespace Avogadro {
namespace QuantumIO {

GaussianCube::GaussianCube()
{
}

GaussianCube::~GaussianCube()
{
}

std::vector<std::string> GaussianCube::fileExtensions() const
{
  std::vector<std::string> extensions;
  extensions.push_back("cube");
  return extensions;
}

std::vector<std::string> GaussianCube::mimeTypes() const
{
  return std::vector<std::string>();
}

bool GaussianCube::read(std::istream &in, Core::Molecule &molecule)
{
  // Variables we will need
  std::string line;
  std::vector<std::string> list;

  int nAtoms;
  Vector3 min;
  Vector3 spacing;
  Vector3i dim;

  // Gaussian Cube format is very specific

  // Read and set name
  getline(in, line);
  molecule.setData("name", line);

  // Read and skip field title (we may be able to use this to setCubeType in the future)
  getline(in, line);

  // Next line contains nAtoms and m_min
  in >> nAtoms;
  for (unsigned int i = 0; i < 3; ++i)
    in >> min(i);
  getline(in, line); //capture newline before continuing

  // Next 3 lines contains spacing and dim
  for (unsigned int i = 0; i < 3; ++i) {
    getline(in, line);
    line = Core::trimmed(line);
    list = Core::split(line, ' ');
    dim(i) = Core::lexicalCast<int>(list[0]);
    spacing(i) = Core::lexicalCast<double>(list[i + 1]);
  }

  // Geometry block
  Vector3 pos;
  for (unsigned int i = 0; i < abs(nAtoms); ++i) {
    getline(in, line);
    line = Core::trimmed(line);
    list = Core::split(line, ' ');
    short int atomNum = Core::lexicalCast<short int>(list[0]);
    Core::Atom a = molecule.addAtom(static_cast<unsigned char>(atomNum));
    for (unsigned int j = 2; j < 5; ++j)
      pos(j - 2) = Core::lexicalCast<double>(list[j]);
    pos = pos * BOHR_TO_ANGSTROM;
    a.setPosition3d(pos);
  }

  // If the nAtoms were negative there is another line before
  // the data which is necessary, maybe contain 1 or more cubes
  unsigned int nCubes = 1;
  if (nAtoms < 0) {
    in >> nCubes;
    std::vector<unsigned int> moList(nCubes);
    for (unsigned int i = 0; i < nCubes; ++i)
      in >> moList[i];
    // clear buffer
    getline(in, line);
  }

  // Render molecule
  molecule.perceiveBondsSimple();

  // Cube block, set limits and populate data
  // min and spacing are in bohr units, convert to ANGSTROM
  for (unsigned int j = 0; j < 3; ++j) {
    min[j] *= BOHR_TO_ANGSTROM;
    spacing[j] *= BOHR_TO_ANGSTROM;
  }

  for (unsigned int i = 0; i < nCubes; ++i){
    // Get a cube object from molecule
    Core::Cube *cube = molecule.addCube();

    cube->setLimits(min, dim, spacing);
    std::vector<double> values;
    // push_back is slow for this, resize vector first
    values.resize(dim(0) * dim(1) * dim(2));
    for (unsigned int j = 0; j < values.size(); ++j)
      in >> values[j];
    // clear buffer, if more than one cube
    getline(in, line);
    cube->setData(values);
  }

  return true;
}

bool GaussianCube::write(std::ostream &out, const Core::Molecule &molecule)
{
    // Not implemented yet
    return false;
}

} // End QuantumIO namespace
} // End Avogadro namespace
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkError.h"
#include "SkPath.h"
#include "SkRect.h"
#include "Test.h"

typedef struct {
    skiatest::Reporter *fReporter;
    unsigned int *fIntPointer;
} ErrorContext;

#define CHECK(errcode)                                                        \
  REPORTER_ASSERT( reporter, (err = SkGetLastError()) == errcode);            \
  if (err != kNoError_SkError)                                                \
  {                                                                           \
     SkClearLastError();                                                      \
  }

static void cb(SkError err, void *context) {
    ErrorContext *context_ptr = static_cast<ErrorContext *>(context);
    REPORTER_ASSERT( context_ptr->fReporter, (*(context_ptr->fIntPointer) == 0xdeadbeef) );
}

DEF_TEST(Error, reporter) {
    SkError err;

    unsigned int test_value = 0xdeadbeef;
    ErrorContext context;
    context.fReporter = reporter;
    context.fIntPointer = &test_value;

    SkSetErrorCallback(cb, &context);

    CHECK(kNoError_SkError);

    SkRect r = SkRect::MakeWH(50, 100);
    CHECK(kNoError_SkError);

    SkPath path;
    path.addRect(r);
    CHECK(kNoError_SkError);

    path.addRoundRect(r, 10, 10);
    CHECK(kNoError_SkError);

    // should trigger the default error callback, which just prints to the screen.
    path.addRoundRect(r, -10, -10);
    CHECK(kInvalidArgument_SkError);
    CHECK(kNoError_SkError);

    // should trigger *our* callback.
    path.addRoundRect(r, -10, -10);
    CHECK(kInvalidArgument_SkError);
    CHECK(kNoError_SkError);
}
<commit_msg>Clear away any lingering error before testing SkError.<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkError.h"
#include "SkPath.h"
#include "SkRect.h"
#include "Test.h"

typedef struct {
    skiatest::Reporter *fReporter;
    unsigned int *fIntPointer;
} ErrorContext;

#define CHECK(errcode)                                                        \
  REPORTER_ASSERT( reporter, (err = SkGetLastError()) == errcode);            \
  if (err != kNoError_SkError)                                                \
  {                                                                           \
     SkClearLastError();                                                      \
  }

static void cb(SkError err, void *context) {
    ErrorContext *context_ptr = static_cast<ErrorContext *>(context);
    REPORTER_ASSERT( context_ptr->fReporter, (*(context_ptr->fIntPointer) == 0xdeadbeef) );
}

DEF_TEST(Error, reporter) {
    // Some previous user of this thread may have left an error laying around.
    SkClearLastError();

    SkError err;

    unsigned int test_value = 0xdeadbeef;
    ErrorContext context;
    context.fReporter = reporter;
    context.fIntPointer = &test_value;

    SkSetErrorCallback(cb, &context);

    CHECK(kNoError_SkError);

    SkRect r = SkRect::MakeWH(50, 100);
    CHECK(kNoError_SkError);

    SkPath path;
    path.addRect(r);
    CHECK(kNoError_SkError);

    path.addRoundRect(r, 10, 10);
    CHECK(kNoError_SkError);

    // should trigger the default error callback, which just prints to the screen.
    path.addRoundRect(r, -10, -10);
    CHECK(kInvalidArgument_SkError);
    CHECK(kNoError_SkError);

    // should trigger *our* callback.
    path.addRoundRect(r, -10, -10);
    CHECK(kInvalidArgument_SkError);
    CHECK(kNoError_SkError);
}
<|endoftext|>


<commit_before>#include <string>
#include <stdexcept>
#include <memory>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "window.h"

//Initialize the unique_ptr's deleters here
std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> Window::mWindow
	= std::unique_ptr<SDL_Window, void (*)(SDL_Window*)>(nullptr, SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> Window::mRenderer
	= std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)>(nullptr, SDL_DestroyRenderer);
//Other static members
SDL_Rect Window::mBox;

Window::Window(){
}
Window::~Window(){
}
void Window::Init(std::string title){
    //initialize all SDL subsystems
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
		throw std::runtime_error("SDL Init Failed");
    if (TTF_Init() == -1)
		throw std::runtime_error("TTF Init Failed");

    //Setup our window
    mBox.x = 0;
    mBox.y = 0;
    mBox.w = 640;
    mBox.h = 480;
    //Create our window
    mWindow.reset(SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        mBox.w, mBox.h, SDL_WINDOW_SHOWN));
    //Make sure it created ok
    if (mWindow == nullptr)
        throw std::runtime_error("Failed to create window");

    //Create the renderer
    mRenderer.reset(SDL_CreateRenderer(mWindow.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
    //Make sure it created ok
    if (mRenderer == nullptr)
        throw std::runtime_error("Failed to create renderer");
}
void Window::Quit(){
    TTF_Quit();
    SDL_Quit();
}
void Window::Draw(SDL_Texture *tex, SDL_Rect &dstRect, SDL_Rect *clip, float angle,
                  int xPivot, int yPivot, SDL_RendererFlip flip)
{
    //Convert pivot pos from relative to object's center to screen space
    xPivot += dstRect.w / 2;
    yPivot += dstRect.h / 2;
    //SDL expects an SDL_Point as the pivot location
    SDL_Point pivot = { xPivot, yPivot };
    //Draw the texture
    SDL_RenderCopyEx(mRenderer.get(), tex, clip, &dstRect, angle, &pivot, flip);
}
SDL_Texture* Window::LoadImage(const std::string &file){
    SDL_Texture* tex = nullptr;
	tex = IMG_LoadTexture(mRenderer.get(), file.c_str());
	if (tex == nullptr)
		throw std::runtime_error("Failed to load image: " + file + IMG_GetError());
	return tex;
}
SDL_Texture* Window::RenderText(const std::string &message, const std::string &fontFile, SDL_Color color, int fontSize){
    //Open the font
	TTF_Font *font = nullptr;
	font = TTF_OpenFont(fontFile.c_str(), fontSize);
	if (font == nullptr)
		throw std::runtime_error("Failed to load font: " + fontFile + TTF_GetError());

	//Render the message to an SDL_Surface, as that's what TTF_RenderText_X returns
	SDL_Surface *surf = TTF_RenderText_Blended(font, message.c_str(), color);
	SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer.get(), surf);
	//Clean up unneeded stuff
	SDL_FreeSurface(surf);
	TTF_CloseFont(font);

	return texture;
}
void Window::Clear(){
    SDL_RenderClear(mRenderer.get());
}
void Window::Present(){
    SDL_RenderPresent(mRenderer.get());
}
SDL_Rect Window::Box(){
    //Update mBox to match the current window size
    SDL_GetWindowSize(mWindow.get(), &mBox.w, &mBox.h);
    return mBox;
}
<commit_msg>minor comment change<commit_after>#include <string>
#include <stdexcept>
#include <memory>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "window.h"

//Initialize the unique_ptr's deleters here
std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> Window::mWindow
	= std::unique_ptr<SDL_Window, void (*)(SDL_Window*)>(nullptr, SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> Window::mRenderer
	= std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)>(nullptr, SDL_DestroyRenderer);
//Other static members
SDL_Rect Window::mBox;

Window::Window(){
}
Window::~Window(){
}
void Window::Init(std::string title){
    //initialize all SDL subsystems
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
		throw std::runtime_error("SDL Init Failed");
    if (TTF_Init() == -1)
		throw std::runtime_error("TTF Init Failed");

    //Setup our window size
    mBox.x = 0;
    mBox.y = 0;
    mBox.w = 640;
    mBox.h = 480;
    //Create our window
    mWindow.reset(SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        mBox.w, mBox.h, SDL_WINDOW_SHOWN));
    //Make sure it created ok
    if (mWindow == nullptr)
        throw std::runtime_error("Failed to create window");

    //Create the renderer
    mRenderer.reset(SDL_CreateRenderer(mWindow.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
    //Make sure it created ok
    if (mRenderer == nullptr)
        throw std::runtime_error("Failed to create renderer");
}
void Window::Quit(){
    TTF_Quit();
    SDL_Quit();
}
void Window::Draw(SDL_Texture *tex, SDL_Rect &dstRect, SDL_Rect *clip, float angle,
                  int xPivot, int yPivot, SDL_RendererFlip flip)
{
    //Convert pivot pos from relative to object's center to screen space
    xPivot += dstRect.w / 2;
    yPivot += dstRect.h / 2;
    //SDL expects an SDL_Point as the pivot location
    SDL_Point pivot = { xPivot, yPivot };
    //Draw the texture
    SDL_RenderCopyEx(mRenderer.get(), tex, clip, &dstRect, angle, &pivot, flip);
}
SDL_Texture* Window::LoadImage(const std::string &file){
    SDL_Texture* tex = nullptr;
	tex = IMG_LoadTexture(mRenderer.get(), file.c_str());
	if (tex == nullptr)
		throw std::runtime_error("Failed to load image: " + file + IMG_GetError());
	return tex;
}
SDL_Texture* Window::RenderText(const std::string &message, const std::string &fontFile, SDL_Color color, int fontSize){
    //Open the font
	TTF_Font *font = nullptr;
	font = TTF_OpenFont(fontFile.c_str(), fontSize);
	if (font == nullptr)
		throw std::runtime_error("Failed to load font: " + fontFile + TTF_GetError());

	//Render the message to an SDL_Surface, as that's what TTF_RenderText_X returns
	SDL_Surface *surf = TTF_RenderText_Blended(font, message.c_str(), color);
	SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer.get(), surf);
	//Clean up unneeded stuff
	SDL_FreeSurface(surf);
	TTF_CloseFont(font);

	return texture;
}
void Window::Clear(){
    SDL_RenderClear(mRenderer.get());
}
void Window::Present(){
    SDL_RenderPresent(mRenderer.get());
}
SDL_Rect Window::Box(){
    //Update mBox to match the current window size
    SDL_GetWindowSize(mWindow.get(), &mBox.w, &mBox.h);
    return mBox;
}
<|endoftext|>


<commit_before>// A helper for the llvm backend

#include <llvm/Transforms/Utils/Cloning.h>
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Utils.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include <llvm/Linker/Linker.h>
#include <llvm/Demangle/Demangle.h>

#include "tlang_util.h"
#include "taichi_llvm_context.h"
#include "backends/llvm_jit.h"

TLANG_NAMESPACE_BEGIN

static llvm::ExitOnError exit_on_err;

TaichiLLVMContext::TaichiLLVMContext(Arch arch) : arch(arch) {
  llvm::InitializeAllTargets();
  llvm::remove_fatal_error_handler();
  llvm::install_fatal_error_handler(
      [](void *user_data, const std::string &reason, bool gen_crash_diag) {
        TC_ERROR("LLVM Fatal Error: {}", reason);
      },
      nullptr);

  if (arch == Arch::x86_64) {
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();
  } else {
#if defined(TLANG_WITH_CUDA)
    LLVMInitializeNVPTXTarget();
    LLVMInitializeNVPTXTargetMC();
    LLVMInitializeNVPTXTargetInfo();
    LLVMInitializeNVPTXAsmPrinter();
#else
	TC_NOT_IMPLEMENTED
#endif
  }
  ctx = std::make_unique<llvm::LLVMContext>();
  TC_INFO("Creating llvm context for arch: {}", arch_name(arch));
  jit = exit_on_err(TaichiLLVMJIT::create(arch));
}

TaichiLLVMContext::~TaichiLLVMContext() {
}

llvm::Type *TaichiLLVMContext::get_data_type(DataType dt) {
  if (dt == DataType::i32) {
    return llvm::Type::getInt32Ty(*ctx);
  } else if (dt == DataType::i8) {
    return llvm::Type::getInt8Ty(*ctx);
  } else if (dt == DataType::i16) {
    return llvm::Type::getInt16Ty(*ctx);
  } else if (dt == DataType::i64) {
    return llvm::Type::getInt64Ty(*ctx);
  } else if (dt == DataType::f32) {
    return llvm::Type::getFloatTy(*ctx);
  } else if (dt == DataType::f64) {
    return llvm::Type::getDoubleTy(*ctx);
  } else {
    TC_INFO(data_type_name(dt));
    TC_NOT_IMPLEMENTED
  }
  return nullptr;
}

std::string find_existing_command(const std::vector<std::string> &commands) {
  for (auto &cmd : commands) {
    if (command_exist(cmd)) {
      return cmd;
    }
  }
  TC_P(commands);
  TC_ERROR("No command found.");
}

std::string get_runtime_fn(Arch arch) {
  return fmt::format("runtime_{}.bc", arch_name(arch));
}

std::string get_runtime_dir() {
  return get_repo_dir() + "/taichi/runtime/";
}

void compile_runtime_bitcode(Arch arch) {
  if (is_release())
    return;
  TI_AUTO_PROF;
  static std::set<int> runtime_compiled;
  if (runtime_compiled.find((int)arch) == runtime_compiled.end()) {
    auto clang = find_existing_command({"clang-7", "clang"});
    TC_ASSERT(command_exist("llvm-as"));
    TC_TRACE("Compiling runtime module bitcode...");
    auto runtime_folder = get_runtime_dir();
    std::string macro = fmt::format(" -D ARCH_{} ", arch_name(arch));
    int ret = std::system(
        fmt::format(
            "{} -S {}runtime.cpp -o {}runtime.ll -emit-llvm -std=c++17 {}",
            clang, runtime_folder, runtime_folder, macro)
            .c_str());
    if (ret) {
      TC_ERROR("Runtime compilation failed.");
    }
    std::system(fmt::format("llvm-as {}runtime.ll -o {}{}", runtime_folder,
                            runtime_folder, get_runtime_fn(arch))
                    .c_str());
    runtime_compiled.insert((int)arch);
  }
}

void compile_runtimes() {
  compile_runtime_bitcode(Arch::x86_64);
#if defined(TLANG_WITH_CUDA)
  compile_runtime_bitcode(Arch::gpu);
#endif
}

std::string libdevice_path() {
#if defined(TLANG_WITH_CUDA)
  auto folder =
      fmt::format("/usr/local/cuda-{}/nvvm/libdevice/", TLANG_CUDA_VERSION);
  if (is_release()) {
    folder = compiled_lib_dir;
  }
  auto cuda_version_major = int(std::atof(TLANG_CUDA_VERSION));
  return fmt::format("{}/libdevice.{}.bc", folder, cuda_version_major);
#else
  TC_NOT_IMPLEMENTED;
  return "";
#endif
}

std::unique_ptr<llvm::Module> TaichiLLVMContext::get_init_module() {
  return clone_runtime_module();
}

std::unique_ptr<llvm::Module> module_from_bitcode_file(std::string bitcode_path,
                                                       llvm::LLVMContext *ctx) {
  TI_AUTO_PROF
  std::ifstream ifs(bitcode_path);
  std::string bitcode(std::istreambuf_iterator<char>(ifs),
                      (std::istreambuf_iterator<char>()));
  auto runtime =
      parseBitcodeFile(MemoryBufferRef(bitcode, "runtime_bitcode"), *ctx);
  if (!runtime) {
    TC_ERROR("Runtime bitcode load failure.");
  }
  bool module_broken = llvm::verifyModule(*runtime.get(), &llvm::errs());
  TC_ERROR_IF(module_broken, "Module broken");
  return std::move(runtime.get());
}

int num_instructions(llvm::Function *func) {
  int counter = 0;
  for (BasicBlock &bb : *func)
    counter += std::distance(bb.begin(), bb.end());
  return counter;
}

void remove_useless_libdevice_functions(llvm::Module *module) {
  std::vector<std::string> function_name_list = {
      "rnorm3df",
      "norm4df",
      "rnorm4df",
      "normf",
      "rnormf",
      "j0f",
      "j1f",
      "y0f",
      "y1f",
      "ynf",
      "jnf",
      "cyl_bessel_i0f",
      "cyl_bessel_i1f",
      "j0",
      "j1",
      "y0",
      "y1",
      "yn",
      "jn",
      "cyl_bessel_i0",
      "cyl_bessel_i1",
      "tgammaf",
      "lgammaf",
      "tgamma",
      "lgamma",
      "erff",
      "erfinvf",
      "erfcf",
      "erfcxf",
      "erfcinvf",
      "erf",
      "erfinv",
      "erfcx",
      "erfcinv",
      "erfc",
  };
  for (auto fn : function_name_list) {
    module->getFunction("__nv_" + fn)->eraseFromParent();
  }
  module->getFunction("__internal_lgamma_pos")->eraseFromParent();
}

std::unique_ptr<llvm::Module> TaichiLLVMContext::clone_runtime_module() {
  TI_AUTO_PROF
  if (!runtime_module) {
    if (is_release()) {
      runtime_module = module_from_bitcode_file(
          fmt::format("{}/{}", compiled_lib_dir, get_runtime_fn(arch)),
          ctx.get());
    } else {
      compile_runtime_bitcode(arch);
      runtime_module = module_from_bitcode_file(
          fmt::format("{}/{}", get_runtime_dir(), get_runtime_fn(arch)),
          ctx.get());
    }
    if (arch == Arch::gpu) {
      runtime_module->setTargetTriple("nvptx64-nvidia-cuda");

      auto patch_intrinsic = [&](std::string name, Intrinsic::ID intrin,
                                 bool ret = true) {
        TC_PROFILER("patch intrinsic");
        auto func = runtime_module->getFunction(name);
        func->getEntryBlock().eraseFromParent();
        auto bb = llvm::BasicBlock::Create(*ctx, "entry", func);
        IRBuilder<> builder(*ctx);
        builder.SetInsertPoint(bb);
        if (ret) {
          builder.CreateRet(builder.CreateIntrinsic(intrin, {}, {}));
        } else {
          builder.CreateIntrinsic(intrin, {}, {});
          builder.CreateRetVoid();
        }
      };

      patch_intrinsic("thread_idx", Intrinsic::nvvm_read_ptx_sreg_tid_x);
      patch_intrinsic("block_idx", Intrinsic::nvvm_read_ptx_sreg_ctaid_x);
      patch_intrinsic("block_dim", Intrinsic::nvvm_read_ptx_sreg_ntid_x);
      patch_intrinsic("grid_dim", Intrinsic::nvvm_read_ptx_sreg_nctaid_x);
      patch_intrinsic("block_barrier", Intrinsic::nvvm_barrier0, false);

      link_module_with_libdevice(runtime_module);

      // runtime_module->print(llvm::errs(), nullptr);
    }

    /*
    int total_inst = 0;
    int total_big_inst = 0;

    for (auto &f : *runtime_module) {
      int c = num_instructions(&f);
      if (c > 100) {
        total_big_inst += c;
        TC_INFO("Loaded runtime function: {} (inst. count= {})",
                std::string(f.getName()), c);
      }
      total_inst += c;
    }
    TC_P(total_inst);
    TC_P(total_big_inst);
    */
  }
  std::unique_ptr<llvm::Module> cloned;
  {
    TC_PROFILER("clone module");
    cloned = llvm::CloneModule(*runtime_module);
  }
  return cloned;
}

void TaichiLLVMContext::link_module_with_libdevice(
    std::unique_ptr<llvm::Module> &module) {
  TI_AUTO_PROF
  auto libdevice_module = module_from_bitcode_file(libdevice_path(), ctx.get());

  remove_useless_libdevice_functions(libdevice_module.get());

  std::vector<std::string> libdevice_function_names;
  for (auto &f : *libdevice_module) {
    if (!f.isDeclaration()) {
      libdevice_function_names.push_back(f.getName());
    }
  }

  libdevice_module->setTargetTriple("nvptx64-nvidia-cuda");
  module->setDataLayout(libdevice_module->getDataLayout());

  bool failed = llvm::Linker::linkModules(*module, std::move(libdevice_module));
  if (failed) {
    TC_ERROR("CUDA libdevice linking failure.");
  }

  for (auto func_name : libdevice_function_names) {
    auto func = module->getFunction(func_name);
    if (!func) {
      TC_P(func_name);
    } else
      func->setLinkage(Function::InternalLinkage);
  }
}

std::unique_ptr<llvm::Module> TaichiLLVMContext::clone_struct_module() {
  TC_ASSERT(struct_module);
  return llvm::CloneModule(*struct_module);
}

void TaichiLLVMContext::set_struct_module(
    const std::unique_ptr<llvm::Module> &module) {
  TC_ASSERT(module);
  if (llvm::verifyModule(*module, &llvm::errs())) {
    module->print(llvm::errs(), nullptr);
    TC_ERROR("module broken");
  }
  struct_module = llvm::CloneModule(*module);
}

template <typename T>
llvm::Value *TaichiLLVMContext::get_constant(DataType dt, T t) {
  if (dt == DataType::f32) {
    return llvm::ConstantFP::get(*ctx, llvm::APFloat((float32)t));
  } else if (dt == DataType::f64) {
    return llvm::ConstantFP::get(*ctx, llvm::APFloat((float64)t));
  } else if (dt == DataType::i32) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(32, t, true));
  } else if (dt == DataType::u32) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(32, t, false));
  } else if (dt == DataType::i64) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(64, t, true));
  } else if (dt == DataType::u64) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(64, t, false));
  } else {
    TC_NOT_IMPLEMENTED
    return nullptr;
  }
}

template llvm::Value *TaichiLLVMContext::get_constant(DataType dt, int32 t);

template <typename T>
llvm::Value *TaichiLLVMContext::get_constant(T t) {
  using TargetType = T;
  if constexpr (std::is_same_v<TargetType, float32> ||
                std::is_same_v<TargetType, float64>) {
    return llvm::ConstantFP::get(*ctx, llvm::APFloat(t));
  } else if (std::is_same_v<TargetType, bool>) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(1, (uint64)t, false));
  } else if (std::is_same_v<TargetType, int32> ||
             std::is_same_v<TargetType, uint32>) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(32, (uint64)t, true));
  } else if (std::is_same_v<TargetType, int64> ||
             std::is_same_v<TargetType, uint64>) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(64, (uint64)t, true));
  } else {
    TC_NOT_IMPLEMENTED
    return nullptr;
  }
}

std::string TaichiLLVMContext::type_name(llvm::Type *type) {
  std::string type_name;
  llvm::raw_string_ostream rso(type_name);
  type->print(rso);
  return rso.str();
}

std::size_t TaichiLLVMContext::get_type_size(llvm::Type *type) {
  return jit->get_type_size(type);
}

template llvm::Value *TaichiLLVMContext::get_constant(float32 t);
template llvm::Value *TaichiLLVMContext::get_constant(float64 t);

template llvm::Value *TaichiLLVMContext::get_constant(bool t);

template llvm::Value *TaichiLLVMContext::get_constant(int32 t);
template llvm::Value *TaichiLLVMContext::get_constant(uint32 t);

template llvm::Value *TaichiLLVMContext::get_constant(int64 t);
template llvm::Value *TaichiLLVMContext::get_constant(uint64 t);

TLANG_NAMESPACE_END
<commit_msg>removed initialize_all_targets<commit_after>// A helper for the llvm backend

#include <llvm/Transforms/Utils/Cloning.h>
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Utils.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include <llvm/Linker/Linker.h>
#include <llvm/Demangle/Demangle.h>

#include "tlang_util.h"
#include "taichi_llvm_context.h"
#include "backends/llvm_jit.h"

TLANG_NAMESPACE_BEGIN

static llvm::ExitOnError exit_on_err;

TaichiLLVMContext::TaichiLLVMContext(Arch arch) : arch(arch) {
  llvm::remove_fatal_error_handler();
  llvm::install_fatal_error_handler(
      [](void *user_data, const std::string &reason, bool gen_crash_diag) {
        TC_ERROR("LLVM Fatal Error: {}", reason);
      },
      nullptr);

  if (arch == Arch::x86_64) {
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();
  } else {
#if defined(TLANG_WITH_CUDA)
    LLVMInitializeNVPTXTarget();
    LLVMInitializeNVPTXTargetMC();
    LLVMInitializeNVPTXTargetInfo();
    LLVMInitializeNVPTXAsmPrinter();
#else
	TC_NOT_IMPLEMENTED
#endif
  }
  ctx = std::make_unique<llvm::LLVMContext>();
  TC_INFO("Creating llvm context for arch: {}", arch_name(arch));
  jit = exit_on_err(TaichiLLVMJIT::create(arch));
}

TaichiLLVMContext::~TaichiLLVMContext() {
}

llvm::Type *TaichiLLVMContext::get_data_type(DataType dt) {
  if (dt == DataType::i32) {
    return llvm::Type::getInt32Ty(*ctx);
  } else if (dt == DataType::i8) {
    return llvm::Type::getInt8Ty(*ctx);
  } else if (dt == DataType::i16) {
    return llvm::Type::getInt16Ty(*ctx);
  } else if (dt == DataType::i64) {
    return llvm::Type::getInt64Ty(*ctx);
  } else if (dt == DataType::f32) {
    return llvm::Type::getFloatTy(*ctx);
  } else if (dt == DataType::f64) {
    return llvm::Type::getDoubleTy(*ctx);
  } else {
    TC_INFO(data_type_name(dt));
    TC_NOT_IMPLEMENTED
  }
  return nullptr;
}

std::string find_existing_command(const std::vector<std::string> &commands) {
  for (auto &cmd : commands) {
    if (command_exist(cmd)) {
      return cmd;
    }
  }
  TC_P(commands);
  TC_ERROR("No command found.");
}

std::string get_runtime_fn(Arch arch) {
  return fmt::format("runtime_{}.bc", arch_name(arch));
}

std::string get_runtime_dir() {
  return get_repo_dir() + "/taichi/runtime/";
}

void compile_runtime_bitcode(Arch arch) {
  if (is_release())
    return;
  TI_AUTO_PROF;
  static std::set<int> runtime_compiled;
  if (runtime_compiled.find((int)arch) == runtime_compiled.end()) {
    auto clang = find_existing_command({"clang-7", "clang"});
    TC_ASSERT(command_exist("llvm-as"));
    TC_TRACE("Compiling runtime module bitcode...");
    auto runtime_folder = get_runtime_dir();
    std::string macro = fmt::format(" -D ARCH_{} ", arch_name(arch));
    int ret = std::system(
        fmt::format(
            "{} -S {}runtime.cpp -o {}runtime.ll -emit-llvm -std=c++17 {}",
            clang, runtime_folder, runtime_folder, macro)
            .c_str());
    if (ret) {
      TC_ERROR("Runtime compilation failed.");
    }
    std::system(fmt::format("llvm-as {}runtime.ll -o {}{}", runtime_folder,
                            runtime_folder, get_runtime_fn(arch))
                    .c_str());
    runtime_compiled.insert((int)arch);
  }
}

void compile_runtimes() {
  compile_runtime_bitcode(Arch::x86_64);
#if defined(TLANG_WITH_CUDA)
  compile_runtime_bitcode(Arch::gpu);
#endif
}

std::string libdevice_path() {
#if defined(TLANG_WITH_CUDA)
  auto folder =
      fmt::format("/usr/local/cuda-{}/nvvm/libdevice/", TLANG_CUDA_VERSION);
  if (is_release()) {
    folder = compiled_lib_dir;
  }
  auto cuda_version_major = int(std::atof(TLANG_CUDA_VERSION));
  return fmt::format("{}/libdevice.{}.bc", folder, cuda_version_major);
#else
  TC_NOT_IMPLEMENTED;
  return "";
#endif
}

std::unique_ptr<llvm::Module> TaichiLLVMContext::get_init_module() {
  return clone_runtime_module();
}

std::unique_ptr<llvm::Module> module_from_bitcode_file(std::string bitcode_path,
                                                       llvm::LLVMContext *ctx) {
  TI_AUTO_PROF
  std::ifstream ifs(bitcode_path);
  std::string bitcode(std::istreambuf_iterator<char>(ifs),
                      (std::istreambuf_iterator<char>()));
  auto runtime =
      parseBitcodeFile(MemoryBufferRef(bitcode, "runtime_bitcode"), *ctx);
  if (!runtime) {
    TC_ERROR("Runtime bitcode load failure.");
  }
  bool module_broken = llvm::verifyModule(*runtime.get(), &llvm::errs());
  TC_ERROR_IF(module_broken, "Module broken");
  return std::move(runtime.get());
}

int num_instructions(llvm::Function *func) {
  int counter = 0;
  for (BasicBlock &bb : *func)
    counter += std::distance(bb.begin(), bb.end());
  return counter;
}

void remove_useless_libdevice_functions(llvm::Module *module) {
  std::vector<std::string> function_name_list = {
      "rnorm3df",
      "norm4df",
      "rnorm4df",
      "normf",
      "rnormf",
      "j0f",
      "j1f",
      "y0f",
      "y1f",
      "ynf",
      "jnf",
      "cyl_bessel_i0f",
      "cyl_bessel_i1f",
      "j0",
      "j1",
      "y0",
      "y1",
      "yn",
      "jn",
      "cyl_bessel_i0",
      "cyl_bessel_i1",
      "tgammaf",
      "lgammaf",
      "tgamma",
      "lgamma",
      "erff",
      "erfinvf",
      "erfcf",
      "erfcxf",
      "erfcinvf",
      "erf",
      "erfinv",
      "erfcx",
      "erfcinv",
      "erfc",
  };
  for (auto fn : function_name_list) {
    module->getFunction("__nv_" + fn)->eraseFromParent();
  }
  module->getFunction("__internal_lgamma_pos")->eraseFromParent();
}

std::unique_ptr<llvm::Module> TaichiLLVMContext::clone_runtime_module() {
  TI_AUTO_PROF
  if (!runtime_module) {
    if (is_release()) {
      runtime_module = module_from_bitcode_file(
          fmt::format("{}/{}", compiled_lib_dir, get_runtime_fn(arch)),
          ctx.get());
    } else {
      compile_runtime_bitcode(arch);
      runtime_module = module_from_bitcode_file(
          fmt::format("{}/{}", get_runtime_dir(), get_runtime_fn(arch)),
          ctx.get());
    }
    if (arch == Arch::gpu) {
      runtime_module->setTargetTriple("nvptx64-nvidia-cuda");

      auto patch_intrinsic = [&](std::string name, Intrinsic::ID intrin,
                                 bool ret = true) {
        TC_PROFILER("patch intrinsic");
        auto func = runtime_module->getFunction(name);
        func->getEntryBlock().eraseFromParent();
        auto bb = llvm::BasicBlock::Create(*ctx, "entry", func);
        IRBuilder<> builder(*ctx);
        builder.SetInsertPoint(bb);
        if (ret) {
          builder.CreateRet(builder.CreateIntrinsic(intrin, {}, {}));
        } else {
          builder.CreateIntrinsic(intrin, {}, {});
          builder.CreateRetVoid();
        }
      };

      patch_intrinsic("thread_idx", Intrinsic::nvvm_read_ptx_sreg_tid_x);
      patch_intrinsic("block_idx", Intrinsic::nvvm_read_ptx_sreg_ctaid_x);
      patch_intrinsic("block_dim", Intrinsic::nvvm_read_ptx_sreg_ntid_x);
      patch_intrinsic("grid_dim", Intrinsic::nvvm_read_ptx_sreg_nctaid_x);
      patch_intrinsic("block_barrier", Intrinsic::nvvm_barrier0, false);

      link_module_with_libdevice(runtime_module);

      // runtime_module->print(llvm::errs(), nullptr);
    }

    /*
    int total_inst = 0;
    int total_big_inst = 0;

    for (auto &f : *runtime_module) {
      int c = num_instructions(&f);
      if (c > 100) {
        total_big_inst += c;
        TC_INFO("Loaded runtime function: {} (inst. count= {})",
                std::string(f.getName()), c);
      }
      total_inst += c;
    }
    TC_P(total_inst);
    TC_P(total_big_inst);
    */
  }
  std::unique_ptr<llvm::Module> cloned;
  {
    TC_PROFILER("clone module");
    cloned = llvm::CloneModule(*runtime_module);
  }
  return cloned;
}

void TaichiLLVMContext::link_module_with_libdevice(
    std::unique_ptr<llvm::Module> &module) {
  TI_AUTO_PROF
  auto libdevice_module = module_from_bitcode_file(libdevice_path(), ctx.get());

  remove_useless_libdevice_functions(libdevice_module.get());

  std::vector<std::string> libdevice_function_names;
  for (auto &f : *libdevice_module) {
    if (!f.isDeclaration()) {
      libdevice_function_names.push_back(f.getName());
    }
  }

  libdevice_module->setTargetTriple("nvptx64-nvidia-cuda");
  module->setDataLayout(libdevice_module->getDataLayout());

  bool failed = llvm::Linker::linkModules(*module, std::move(libdevice_module));
  if (failed) {
    TC_ERROR("CUDA libdevice linking failure.");
  }

  for (auto func_name : libdevice_function_names) {
    auto func = module->getFunction(func_name);
    if (!func) {
      TC_P(func_name);
    } else
      func->setLinkage(Function::InternalLinkage);
  }
}

std::unique_ptr<llvm::Module> TaichiLLVMContext::clone_struct_module() {
  TC_ASSERT(struct_module);
  return llvm::CloneModule(*struct_module);
}

void TaichiLLVMContext::set_struct_module(
    const std::unique_ptr<llvm::Module> &module) {
  TC_ASSERT(module);
  if (llvm::verifyModule(*module, &llvm::errs())) {
    module->print(llvm::errs(), nullptr);
    TC_ERROR("module broken");
  }
  struct_module = llvm::CloneModule(*module);
}

template <typename T>
llvm::Value *TaichiLLVMContext::get_constant(DataType dt, T t) {
  if (dt == DataType::f32) {
    return llvm::ConstantFP::get(*ctx, llvm::APFloat((float32)t));
  } else if (dt == DataType::f64) {
    return llvm::ConstantFP::get(*ctx, llvm::APFloat((float64)t));
  } else if (dt == DataType::i32) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(32, t, true));
  } else if (dt == DataType::u32) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(32, t, false));
  } else if (dt == DataType::i64) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(64, t, true));
  } else if (dt == DataType::u64) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(64, t, false));
  } else {
    TC_NOT_IMPLEMENTED
    return nullptr;
  }
}

template llvm::Value *TaichiLLVMContext::get_constant(DataType dt, int32 t);

template <typename T>
llvm::Value *TaichiLLVMContext::get_constant(T t) {
  using TargetType = T;
  if constexpr (std::is_same_v<TargetType, float32> ||
                std::is_same_v<TargetType, float64>) {
    return llvm::ConstantFP::get(*ctx, llvm::APFloat(t));
  } else if (std::is_same_v<TargetType, bool>) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(1, (uint64)t, false));
  } else if (std::is_same_v<TargetType, int32> ||
             std::is_same_v<TargetType, uint32>) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(32, (uint64)t, true));
  } else if (std::is_same_v<TargetType, int64> ||
             std::is_same_v<TargetType, uint64>) {
    return llvm::ConstantInt::get(*ctx, llvm::APInt(64, (uint64)t, true));
  } else {
    TC_NOT_IMPLEMENTED
    return nullptr;
  }
}

std::string TaichiLLVMContext::type_name(llvm::Type *type) {
  std::string type_name;
  llvm::raw_string_ostream rso(type_name);
  type->print(rso);
  return rso.str();
}

std::size_t TaichiLLVMContext::get_type_size(llvm::Type *type) {
  return jit->get_type_size(type);
}

template llvm::Value *TaichiLLVMContext::get_constant(float32 t);
template llvm::Value *TaichiLLVMContext::get_constant(float64 t);

template llvm::Value *TaichiLLVMContext::get_constant(bool t);

template llvm::Value *TaichiLLVMContext::get_constant(int32 t);
template llvm::Value *TaichiLLVMContext::get_constant(uint32 t);

template llvm::Value *TaichiLLVMContext::get_constant(int64 t);
template llvm::Value *TaichiLLVMContext::get_constant(uint64 t);

TLANG_NAMESPACE_END
<|endoftext|>


<commit_before>/* Copyright 2016 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file Model.cpp
 *
 *  @author Kristofer Björnson
 */

#include "Geometry.h"
#include "Model.h"
#include "Streams.h"
#include "TBTKMacros.h"

#include <fstream>
#include <math.h>
#include <string>

using namespace std;

namespace TBTK{

Model::Model(){
	temperature = 0.;
	chemicalPotential = 0.;
	statistics = Statistics::FermiDirac;
	amplitudeSet = new AmplitudeSet();
	geometry = NULL;
	isTalkative = true;
}

Model::~Model(){
	delete amplitudeSet;
	if(geometry != NULL)
		delete geometry;
}

/*void Model::addHA(HoppingAmplitude ha){
	amplitudeSet.addHA(ha);
}

void Model::addHAAndHC(HoppingAmplitude ha){
	amplitudeSet.addHAAndHC(ha);
}*/

void Model::construct(){
	if(isTalkative)
		Streams::out << "Constructing system\n";

	amplitudeSet->construct();

	int basisSize = getBasisSize();

	if(isTalkative)
		Streams::out << "\tBasis size: " << basisSize << "\n";
}

void Model::createGeometry(int dimensions, int numSpecifiers){
	TBTKAssert(
		getIsConstructed(),
		"Model::createGeometry()",
		"Hilbert space basis has not been constructed yet.",
		""
	);

	geometry = new Geometry(dimensions, numSpecifiers, this);
}

};	//End of namespace TBTK
<commit_msg>Removed commented out legacy code<commit_after>/* Copyright 2016 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file Model.cpp
 *
 *  @author Kristofer Björnson
 */

#include "Geometry.h"
#include "Model.h"
#include "Streams.h"
#include "TBTKMacros.h"

#include <fstream>
#include <math.h>
#include <string>

using namespace std;

namespace TBTK{

Model::Model(){
	temperature = 0.;
	chemicalPotential = 0.;
	statistics = Statistics::FermiDirac;
	amplitudeSet = new AmplitudeSet();
	geometry = NULL;
	isTalkative = true;
}

Model::~Model(){
	delete amplitudeSet;
	if(geometry != NULL)
		delete geometry;
}

void Model::construct(){
	if(isTalkative)
		Streams::out << "Constructing system\n";

	amplitudeSet->construct();

	int basisSize = getBasisSize();

	if(isTalkative)
		Streams::out << "\tBasis size: " << basisSize << "\n";
}

void Model::createGeometry(int dimensions, int numSpecifiers){
	TBTKAssert(
		getIsConstructed(),
		"Model::createGeometry()",
		"Hilbert space basis has not been constructed yet.",
		""
	);

	geometry = new Geometry(dimensions, numSpecifiers, this);
}

};	//End of namespace TBTK
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestBoostAdapter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/
#include "vtkGraph.h"
#include "vtkGraphToBoostAdapter.h"
#include "vtkIntArray.h"
#include "vtkIdTypeArray.h"
#include "vtkMath.h"
#include "vtkTimerLog.h"
#include "vtkTreeToBoostAdapter.h"

#include "vtkSmartPointer.h"
#define VTK_CREATE(type, name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

#include <vtksys/stl/vector>
#include <vtksys/stl/map>
#include <vtksys/stl/utility>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/transitive_closure.hpp>
#include <boost/graph/sequential_vertex_coloring.hpp>
#include <boost/property_map.hpp>
#include <boost/vector_property_map.hpp>

using namespace boost;
using namespace vtksys_stl;

template <typename Graph>
void TestTraversal(Graph g, int repeat, int& vtkNotUsed(errors))
{
  typedef typename graph_traits<Graph>::edge_descriptor Edge;
  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

  VTK_CREATE(vtkTimerLog, timer);
  typename graph_traits<Graph>::vertex_iterator vi, viEnd;

  // Traverse the edge list of each vertex
  timer->StartTimer();
  int count = 0;
  for (int r = 0; r < repeat; r++)
    {
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      tie(oi, oiEnd) = out_edges(*vi, g);
      count++;
      }
    }
  timer->StopTimer();
  double time_out_edges = timer->GetElapsedTime();
  cerr << "getting out edges: " << time_out_edges / count << " sec." << endl;

  Edge e = *(edges(g).first);
  Vertex v = *(vertices(g).first);
  vector<Edge> edge_vec;
  vector<Vertex> vert_vec;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_inc = timer->GetElapsedTime();
  cerr << "+increment: " << time_inc / count << " sec." << endl;
  cerr << "  just increment: " << (time_inc - time_out_edges) / count << " sec." << endl;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    edge_vec.clear();
    vert_vec.clear();
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        edge_vec.push_back(e);
        vert_vec.push_back(v);
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_push_back = timer->GetElapsedTime();
  cerr << "+push_back: " << time_push_back / count << " sec." << endl;
  cerr << "  just push_back: " << (time_push_back - time_inc) / count << " sec." << endl;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    edge_vec.clear();
    vert_vec.clear();
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        Edge e1 = *oi;
        edge_vec.push_back(e1);
        vert_vec.push_back(v);
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_deref = timer->GetElapsedTime();
  cerr << "+dereference: " << time_deref / count << " sec." << endl;
  cerr << "  just dereference: " << (time_deref - time_push_back) / count << " sec." << endl;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    edge_vec.clear();
    vert_vec.clear();
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        Edge e1 = *oi;
        edge_vec.push_back(e1);
        Vertex v1 = target(e1, g);
        vert_vec.push_back(v1);
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_target = timer->GetElapsedTime();
  cerr << "+target: " << time_target / count << " sec." << endl;
  cerr << "  just target: " << (time_target - time_deref) / count << " sec." << endl;
}

template <typename Graph>
void TestGraph(Graph g, vtkIdType numVertices, vtkIdType numEdges, int repeat, int& errors)
{
  typedef typename graph_traits<Graph>::edge_descriptor Edge;
  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

  VTK_CREATE(vtkTimerLog, timer);

  vector<Vertex> graphVerts;
  vector<Edge> graphEdges;
  typename graph_traits<Graph>::vertex_iterator vi, viEnd;

  // Create a graph
  timer->StartTimer();
  for (int i = 0; i < numVertices; ++i)
    {
    add_vertex(g);
    }
  timer->StopTimer();
  cerr << "vertex insertion: " << timer->GetElapsedTime() / numVertices  << " sec." << endl;

  if (static_cast<int>(num_vertices(g)) != numVertices)
    {
    cerr << "ERROR: Number of vertices (" << num_vertices(g)
         << ") not as expected (" << numVertices << ")." << endl;
    errors++;
    }

  for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
    {
    graphVerts.push_back(*vi);
    }

  timer->StartTimer();
  for (int i = 0; i < numEdges; ++i)
    {
    int u = static_cast<int>(vtkMath::Random(0, numVertices));
    int v = static_cast<int>(vtkMath::Random(0, numVertices));
    add_edge(graphVerts[u], graphVerts[v], g);
    }
  timer->StopTimer();
  cerr << "edge insertion: " << timer->GetElapsedTime() / numEdges  << " sec." << endl;

  if (static_cast<int>(num_edges(g)) != numEdges)
    {
    cerr << "ERROR: Number of edges (" << num_edges(g)
         << ") not as expected (" << numEdges << ")." << endl;
    errors++;
    }

  typename graph_traits<Graph>::edge_iterator ei, eiEnd;
  for (tie(ei, eiEnd) = edges(g); ei != eiEnd; ++ei)
    {
    graphEdges.push_back(*ei);
    }

  TestTraversal(g, repeat, errors);

  timer->StartTimer();
  while (num_edges(g) > 0)
    {
    remove_edge(*(edges(g).first), g);
    }
  timer->StopTimer();
  cerr << "edge deletion: " << timer->GetElapsedTime() / numEdges  << " sec." << endl;

  // Perform edge deletions followed by accesses
  timer->StartTimer();
  while (num_vertices(g) > 0)
    {
    remove_vertex(*(vertices(g).first), g);
    }
  timer->StopTimer();
  cerr << "vertex deletion: " << timer->GetElapsedTime() / numVertices  << " sec." << endl;
}

int TestBoostAdapter(int vtkNotUsed(argc), char* vtkNotUsed(argv)[])
{
  int errors = 0;
  int repeat = 100;
  vtkIdType numVertices = 1000;
  vtkIdType numEdges = 2000;

  cerr << "Testing boost list graph..." << endl;
  typedef adjacency_list<listS, listS, directedS, property<vertex_index_t, unsigned int>, property<edge_index_t, unsigned int>, no_property, listS> ListGraph;
  ListGraph listGraph;
  TestGraph(listGraph, numVertices, numEdges, repeat, errors);
  cerr << "...done." << endl << endl;

  cerr << "Testing boost vector graph..." << endl;
  typedef adjacency_list<vecS, vecS, directedS, property<vertex_index_t, unsigned int>, property<edge_index_t, unsigned int>, no_property, vecS> VectorGraph;
  VectorGraph vectorGraph;
  TestGraph(vectorGraph, numVertices, numEdges, repeat, errors);
  cerr << "...done." << endl << endl;

  cerr << "Testing undirected graph adapter..." << endl;
  vtkGraph* ug = vtkGraph::New();
  ug->SetDirected(false);
  vtkBoostUndirectedGraph ugBoost(ug);
  TestGraph(ugBoost, numVertices, numEdges, repeat, errors);
  ug->Delete();
  cerr << "...done." << endl << endl;

  cerr << "Testing directed graph adapter..." << endl;
  vtkGraph* dg = vtkGraph::New();
  dg->SetDirected(true);
  vtkBoostDirectedGraph dgBoost(dg);
  TestGraph(dgBoost, numVertices, numEdges, repeat, errors);
  dg->Delete();
  cerr << "...done." << endl << endl;

  cerr << "Testing tree adapter..." << endl;
  vtkTree* t = vtkTree::New();
  t->AddRoot();
  for (vtkIdType i = 1; i < numVertices; i++)
    {
    t->AddChild(static_cast<vtkIdType>(vtkMath::Random(0, i)));
    }
  TestTraversal(t, repeat, errors);
  t->Delete();
  cerr << "...done." << endl << endl;

  return errors;
}
<commit_msg>COMP: Remove sequential_vertex_coloring.hpp from the include line since it breaks the compile with boost 1.32 and isn't actually used anywhere in the code<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestBoostAdapter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include <vtksys/stl/vector>
#include <vtksys/stl/map>
#include <vtksys/stl/utility>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/transitive_closure.hpp>
// #include <boost/graph/sequential_vertex_coloring.hpp>
#include <boost/property_map.hpp>
#include <boost/vector_property_map.hpp>

#include "vtkGraph.h"
#include "vtkGraphToBoostAdapter.h"
#include "vtkIntArray.h"
#include "vtkIdTypeArray.h"
#include "vtkMath.h"
#include "vtkTimerLog.h"
#include "vtkTreeToBoostAdapter.h"

#include "vtkSmartPointer.h"
#define VTK_CREATE(type, name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

using namespace boost;
using namespace vtksys_stl;

template <typename Graph>
void TestTraversal(Graph g, int repeat, int& vtkNotUsed(errors))
{
  typedef typename graph_traits<Graph>::edge_descriptor Edge;
  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

  VTK_CREATE(vtkTimerLog, timer);
  typename graph_traits<Graph>::vertex_iterator vi, viEnd;

  // Traverse the edge list of each vertex
  timer->StartTimer();
  int count = 0;
  for (int r = 0; r < repeat; r++)
    {
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      tie(oi, oiEnd) = out_edges(*vi, g);
      count++;
      }
    }
  timer->StopTimer();
  double time_out_edges = timer->GetElapsedTime();
  cerr << "getting out edges: " << time_out_edges / count << " sec." << endl;

  Edge e = *(edges(g).first);
  Vertex v = *(vertices(g).first);
  vector<Edge> edge_vec;
  vector<Vertex> vert_vec;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_inc = timer->GetElapsedTime();
  cerr << "+increment: " << time_inc / count << " sec." << endl;
  cerr << "  just increment: " << (time_inc - time_out_edges) / count << " sec." << endl;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    edge_vec.clear();
    vert_vec.clear();
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        edge_vec.push_back(e);
        vert_vec.push_back(v);
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_push_back = timer->GetElapsedTime();
  cerr << "+push_back: " << time_push_back / count << " sec." << endl;
  cerr << "  just push_back: " << (time_push_back - time_inc) / count << " sec." << endl;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    edge_vec.clear();
    vert_vec.clear();
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        Edge e1 = *oi;
        edge_vec.push_back(e1);
        vert_vec.push_back(v);
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_deref = timer->GetElapsedTime();
  cerr << "+dereference: " << time_deref / count << " sec." << endl;
  cerr << "  just dereference: " << (time_deref - time_push_back) / count << " sec." << endl;

  timer->StartTimer();
  count = 0;
  for (int r = 0; r < repeat; r++)
    {
    edge_vec.clear();
    vert_vec.clear();
    for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
      {
      typename graph_traits<Graph>::out_edge_iterator oi, oiEnd;
      for (tie(oi, oiEnd) = out_edges(*vi, g); oi != oiEnd; ++oi)
        {
        Edge e1 = *oi;
        edge_vec.push_back(e1);
        Vertex v1 = target(e1, g);
        vert_vec.push_back(v1);
        count++;
        }
      }
    }
  timer->StopTimer();
  double time_target = timer->GetElapsedTime();
  cerr << "+target: " << time_target / count << " sec." << endl;
  cerr << "  just target: " << (time_target - time_deref) / count << " sec." << endl;
}

template <typename Graph>
void TestGraph(Graph g, vtkIdType numVertices, vtkIdType numEdges, int repeat, int& errors)
{
  typedef typename graph_traits<Graph>::edge_descriptor Edge;
  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

  VTK_CREATE(vtkTimerLog, timer);

  vector<Vertex> graphVerts;
  vector<Edge> graphEdges;
  typename graph_traits<Graph>::vertex_iterator vi, viEnd;

  // Create a graph
  timer->StartTimer();
  for (int i = 0; i < numVertices; ++i)
    {
    add_vertex(g);
    }
  timer->StopTimer();
  cerr << "vertex insertion: " << timer->GetElapsedTime() / numVertices  << " sec." << endl;

  if (static_cast<int>(num_vertices(g)) != numVertices)
    {
    cerr << "ERROR: Number of vertices (" << num_vertices(g)
         << ") not as expected (" << numVertices << ")." << endl;
    errors++;
    }

  for (tie(vi, viEnd) = vertices(g); vi != viEnd; ++vi)
    {
    graphVerts.push_back(*vi);
    }

  timer->StartTimer();
  for (int i = 0; i < numEdges; ++i)
    {
    int u = static_cast<int>(vtkMath::Random(0, numVertices));
    int v = static_cast<int>(vtkMath::Random(0, numVertices));
    add_edge(graphVerts[u], graphVerts[v], g);
    }
  timer->StopTimer();
  cerr << "edge insertion: " << timer->GetElapsedTime() / numEdges  << " sec." << endl;

  if (static_cast<int>(num_edges(g)) != numEdges)
    {
    cerr << "ERROR: Number of edges (" << num_edges(g)
         << ") not as expected (" << numEdges << ")." << endl;
    errors++;
    }

  typename graph_traits<Graph>::edge_iterator ei, eiEnd;
  for (tie(ei, eiEnd) = edges(g); ei != eiEnd; ++ei)
    {
    graphEdges.push_back(*ei);
    }

  TestTraversal(g, repeat, errors);

  timer->StartTimer();
  while (num_edges(g) > 0)
    {
    remove_edge(*(edges(g).first), g);
    }
  timer->StopTimer();
  cerr << "edge deletion: " << timer->GetElapsedTime() / numEdges  << " sec." << endl;

  // Perform edge deletions followed by accesses
  timer->StartTimer();
  while (num_vertices(g) > 0)
    {
    remove_vertex(*(vertices(g).first), g);
    }
  timer->StopTimer();
  cerr << "vertex deletion: " << timer->GetElapsedTime() / numVertices  << " sec." << endl;
}

int TestBoostAdapter(int vtkNotUsed(argc), char* vtkNotUsed(argv)[])
{
  int errors = 0;
  int repeat = 100;
  vtkIdType numVertices = 1000;
  vtkIdType numEdges = 2000;

  cerr << "Testing boost list graph..." << endl;
  typedef adjacency_list<listS, listS, directedS, property<vertex_index_t, unsigned int>, property<edge_index_t, unsigned int>, no_property, listS> ListGraph;
  ListGraph listGraph;
  TestGraph(listGraph, numVertices, numEdges, repeat, errors);
  cerr << "...done." << endl << endl;

  cerr << "Testing boost vector graph..." << endl;
  typedef adjacency_list<vecS, vecS, directedS, property<vertex_index_t, unsigned int>, property<edge_index_t, unsigned int>, no_property, vecS> VectorGraph;
  VectorGraph vectorGraph;
  TestGraph(vectorGraph, numVertices, numEdges, repeat, errors);
  cerr << "...done." << endl << endl;

  cerr << "Testing undirected graph adapter..." << endl;
  vtkGraph* ug = vtkGraph::New();
  ug->SetDirected(false);
  vtkBoostUndirectedGraph ugBoost(ug);
  TestGraph(ugBoost, numVertices, numEdges, repeat, errors);
  ug->Delete();
  cerr << "...done." << endl << endl;

  cerr << "Testing directed graph adapter..." << endl;
  vtkGraph* dg = vtkGraph::New();
  dg->SetDirected(true);
  vtkBoostDirectedGraph dgBoost(dg);
  TestGraph(dgBoost, numVertices, numEdges, repeat, errors);
  dg->Delete();
  cerr << "...done." << endl << endl;

  cerr << "Testing tree adapter..." << endl;
  vtkTree* t = vtkTree::New();
  t->AddRoot();
  for (vtkIdType i = 1; i < numVertices; i++)
    {
    t->AddChild(static_cast<vtkIdType>(vtkMath::Random(0, i)));
    }
  TestTraversal(t, repeat, errors);
  t->Delete();
  cerr << "...done." << endl << endl;

  return errors;
}
<|endoftext|>


<commit_before>/* Copyright 2017-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0. */
#include "watchman_system.h"
#include <folly/logging/xlog.h>
#include <folly/portability/GTest.h>
#include <list>
#include "ChildProcess.h"

using watchman::ChildProcess;
using Environment = ChildProcess::Environment;
using Options = ChildProcess::Options;

TEST(ChildProcess, pipe) {
  Options opts;
  opts.pipeStdout();
  ChildProcess echo(
      {
#ifndef _WIN32
          "/bin/echo",
#else
          // If we're being built via cmake we know that we
          // have the cmake executable on hand to invoke its
          // echo program
          "cmake",
          "-E",
          "echo",
#endif
          "hello"},
      std::move(opts));

  auto outputs = echo.communicate();
  echo.wait();

  w_string_piece line(outputs.first);
  EXPECT_TRUE(line.startsWith("hello"));
}

void test_pipe_input(bool threaded) {
#ifndef _WIN32
  Options opts;
  opts.pipeStdout();
  opts.pipeStdin();
  ChildProcess cat({"/bin/cat", "-"}, std::move(opts));

  std::vector<std::string> expected{"one", "two", "three"};
  std::list<std::string> lines{"one\n", "two\n", "three\n"};

  auto writable = [&lines](watchman::FileDescriptor& fd) {
    if (lines.empty()) {
      return true;
    }
    auto str = lines.front();
    if (write(fd.fd(), str.data(), str.size()) == -1) {
      throw std::runtime_error("write to child failed");
    }
    lines.pop_front();
    return false;
  };

  auto outputs =
      threaded ? cat.threadedCommunicate(writable) : cat.communicate(writable);
  cat.wait();

  std::vector<std::string> resultLines;
  w_string_piece(outputs.first).split(resultLines, '\n');
  EXPECT_EQ(resultLines.size(), 3);
  EXPECT_EQ(resultLines, expected);
#else
  (void)threaded;
#endif
}

TEST(ChildProcess, stresstest_pipe_output) {
  bool okay = true;
#ifndef _WIN32
  for (int i = 0; i < 3000; ++i) {
    Options opts;
    opts.pipeStdout();
    ChildProcess proc(
        {"/usr/bin/head", "-n20", "/dev/urandom"}, std::move(opts));
    auto outputs = proc.communicate();
    w_string_piece out(outputs.first);
    proc.wait();
    if (out.empty() || out[out.size() - 1] != '\n') {
      okay = false;
      break;
    }
  }
#endif
  EXPECT_TRUE(okay);
}

TEST(ChildProcess, inputThreaded) {
  test_pipe_input(true);
}

TEST(ChildProcess, inputNotThreaded) {
  test_pipe_input(false);
}
<commit_msg>watchman: resolve posix utilities from path in tests<commit_after>/* Copyright 2017-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0. */
#include "watchman_system.h"
#include <folly/logging/xlog.h>
#include <folly/portability/GTest.h>
#include <list>
#include "ChildProcess.h"

using watchman::ChildProcess;
using Environment = ChildProcess::Environment;
using Options = ChildProcess::Options;

TEST(ChildProcess, pipe) {
  Options opts;
  opts.pipeStdout();
  ChildProcess echo(
      {
#ifndef _WIN32
          "echo",
#else
          // If we're being built via cmake we know that we
          // have the cmake executable on hand to invoke its
          // echo program
          "cmake",
          "-E",
          "echo",
#endif
          "hello"},
      std::move(opts));

  auto outputs = echo.communicate();
  echo.wait();

  w_string_piece line(outputs.first);
  EXPECT_TRUE(line.startsWith("hello"));
}

void test_pipe_input(bool threaded) {
#ifndef _WIN32
  Options opts;
  opts.pipeStdout();
  opts.pipeStdin();
  ChildProcess cat({"cat", "-"}, std::move(opts));

  std::vector<std::string> expected{"one", "two", "three"};
  std::list<std::string> lines{"one\n", "two\n", "three\n"};

  auto writable = [&lines](watchman::FileDescriptor& fd) {
    if (lines.empty()) {
      return true;
    }
    auto str = lines.front();
    if (write(fd.fd(), str.data(), str.size()) == -1) {
      throw std::runtime_error("write to child failed");
    }
    lines.pop_front();
    return false;
  };

  auto outputs =
      threaded ? cat.threadedCommunicate(writable) : cat.communicate(writable);
  cat.wait();

  std::vector<std::string> resultLines;
  w_string_piece(outputs.first).split(resultLines, '\n');
  EXPECT_EQ(resultLines.size(), 3);
  EXPECT_EQ(resultLines, expected);
#else
  (void)threaded;
#endif
}

TEST(ChildProcess, stresstest_pipe_output) {
  bool okay = true;
#ifndef _WIN32
  for (int i = 0; i < 3000; ++i) {
    Options opts;
    opts.pipeStdout();
    ChildProcess proc({"head", "-n20", "/dev/urandom"}, std::move(opts));
    auto outputs = proc.communicate();
    w_string_piece out(outputs.first);
    proc.wait();
    if (out.empty() || out[out.size() - 1] != '\n') {
      okay = false;
      break;
    }
  }
#endif
  EXPECT_TRUE(okay);
}

TEST(ChildProcess, inputThreaded) {
  test_pipe_input(true);
}

TEST(ChildProcess, inputNotThreaded) {
  test_pipe_input(false);
}
<|endoftext|>