<commit_before>/*************************************************************************
 *
 *  $RCSfile: intercept.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: abi $ $Date: 2003-04-04 11:41:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#include "intercept.hxx"
#ifndef _EMBEDDOC_HXX_
#include "embeddoc.hxx"
#endif
#ifndef _DOCHOLDER_HXX_
#include "docholder.hxx"
#endif

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

#define IUL 5

uno::Sequence<::rtl::OUString> Interceptor::m_aInterceptedURL(IUL);

struct equalOUString
{
    bool operator()(
        const rtl::OUString& rKey1,
        const rtl::OUString& rKey2 ) const
    {
        return !!( rKey1 == rKey2 );
    }
};

struct hashOUString
{
    size_t operator()( const rtl::OUString& rName ) const
    {
        return rName.hashCode();
    }
};

class StatusChangeListenerContainer
    : public ::cppu::OMultiTypeInterfaceContainerHelperVar<
rtl::OUString,hashOUString,equalOUString>
{
public:
    StatusChangeListenerContainer( ::osl::Mutex& aMutex )
        :  cppu::OMultiTypeInterfaceContainerHelperVar<
    rtl::OUString,hashOUString,equalOUString>(aMutex)
    {
    }
};

void SAL_CALL
Interceptor::addEventListener(
    const uno::Reference<lang::XEventListener >& Listener )
    throw( uno::RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( ! m_pDisposeEventListeners )
        m_pDisposeEventListeners =
            new cppu::OInterfaceContainerHelper( m_aMutex );

    m_pDisposeEventListeners->addInterface( Listener );
}

void SAL_CALL
Interceptor::removeEventListener(
    const uno::Reference< lang::XEventListener >& Listener )
    throw( uno::RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( m_pDisposeEventListeners )
        m_pDisposeEventListeners->removeInterface( Listener );
}

void SAL_CALL Interceptor::dispose()
{
    lang::EventObject aEvt;
    aEvt.Source = static_cast< frame::XDispatch* >( this );

    osl::MutexGuard aGuard(m_aMutex);

    if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
        m_pDisposeEventListeners->disposeAndClear( aEvt );

    if(m_pStatCL)
        m_pStatCL->disposeAndClear( aEvt );

    m_xSlaveDispatchProvider = 0;
    m_xMasterDispatchProvider = 0;
}

Interceptor::Interceptor(
    EmbedDocument_Impl* pOLEInterface,
    DocumentHolder* pDocH)
    : m_pOLEInterface(pOLEInterface),
      m_pDocH(pDocH),
      m_pStatCL(0),
      m_pDisposeEventListeners(0)
{
    m_aInterceptedURL[0] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:Save"));
    m_aInterceptedURL[1] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:SaveAll"));
    m_aInterceptedURL[2] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:CloseDoc"));
    m_aInterceptedURL[3] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:CloseWin"));
    m_aInterceptedURL[4] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:CloseFrame"));
}

Interceptor::~Interceptor()
{
    if( m_pDisposeEventListeners )
        delete m_pDisposeEventListeners;

    if(m_pStatCL)
        delete m_pStatCL;

    m_pDocH->ClearInterceptor();
}

//XDispatch
void SAL_CALL
Interceptor::dispatch(
    const util::URL& URL,
    const uno::Sequence<
    beans::PropertyValue >& Arguments )
    throw (uno::RuntimeException)
{
    if(m_pOLEInterface)
        if(URL.Complete == m_aInterceptedURL[0])
            m_pOLEInterface->SaveObject();
        else if(URL.Complete == m_aInterceptedURL[2] ||
                URL.Complete == m_aInterceptedURL[3] ||
                URL.Complete == m_aInterceptedURL[4])
            m_pOLEInterface->Close(1);
}

void Interceptor::generateFeatureStateEvent()
{
    if(m_pStatCL)
    {
        for(int i = 0; i < IUL; ++i)
        {
            if( i == 1 )
                continue;

            cppu::OInterfaceContainerHelper* pICH =
                m_pStatCL->getContainer(m_aInterceptedURL[i]);
            uno::Sequence<uno::Reference<uno::XInterface> > aSeq;
            if(pICH)
                aSeq = pICH->getElements();
            if(!aSeq.getLength())
                continue;

            frame::FeatureStateEvent aStateEvent;
            aStateEvent.IsEnabled = sal_True;
            aStateEvent.Requery = sal_False;
            if(i == 0)
            {

                aStateEvent.FeatureURL.Complete = m_aInterceptedURL[0];
                aStateEvent.FeatureDescriptor = rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("Update"));
                aStateEvent.State <<= (rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("($1) ")) +
                                       m_pDocH->getTitle());

            }
            else
            {
                frame::FeatureStateEvent aStateEvent;
                aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
                aStateEvent.FeatureDescriptor = rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
                aStateEvent.State <<= (rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("($2) ")) +
                                       m_pDocH->getTitle());

            }

            for(sal_Int32 k = 0; k < aSeq.getLength(); ++k)
            {
                uno::Reference<frame::XStatusListener>
                    Control(aSeq[k],uno::UNO_QUERY);
                if(Control.is())
                    Control->statusChanged(aStateEvent);

            }
        }
    }
}

void SAL_CALL
Interceptor::addStatusListener(
    const uno::Reference<
    frame::XStatusListener >& Control,
    const util::URL& URL )
    throw (
        uno::RuntimeException
    )
{
    if(!Control.is())
        return;

    if(URL.Complete == m_aInterceptedURL[0])
    {   // Save
        frame::FeatureStateEvent aStateEvent;
        aStateEvent.FeatureURL.Complete = m_aInterceptedURL[0];
        aStateEvent.FeatureDescriptor = rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("Update"));
        aStateEvent.IsEnabled = sal_True;
        aStateEvent.Requery = sal_False;
        aStateEvent.State <<= (rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("($1) ")) +
                               m_pDocH->getTitle());
        Control->statusChanged(aStateEvent);

        {
            osl::MutexGuard aGuard(m_aMutex);
            if(!m_pStatCL)
                m_pStatCL =
                    new StatusChangeListenerContainer(m_aMutex);
        }

        m_pStatCL->addInterface(URL.Complete,Control);
        return;
    }

    sal_Int32 i = 2;
    if(URL.Complete == m_aInterceptedURL[i] ||
       URL.Complete == m_aInterceptedURL[++i] ||
       URL.Complete == m_aInterceptedURL[++i] )
    {   // Close and return
        frame::FeatureStateEvent aStateEvent;
        aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
        aStateEvent.FeatureDescriptor = rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
        aStateEvent.IsEnabled = sal_True;
        aStateEvent.Requery = sal_False;
        aStateEvent.State <<= (rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("($2) ")) +
                               m_pDocH->getTitle());
        Control->statusChanged(aStateEvent);

        {
            osl::MutexGuard aGuard(m_aMutex);
            if(!m_pStatCL)
                m_pStatCL =
                    new StatusChangeListenerContainer(m_aMutex);
        }

        m_pStatCL->addInterface(URL.Complete,Control);
        return;
    }
}

void SAL_CALL
Interceptor::removeStatusListener(
    const uno::Reference<
    frame::XStatusListener >& Control,
    const util::URL& URL )
    throw (
        uno::RuntimeException
    )
{
    if(!(Control.is() && m_pStatCL))
        return;
    else {
        m_pStatCL->removeInterface(URL.Complete,Control);
        return;
    }
}

//XInterceptorInfo
uno::Sequence< ::rtl::OUString >
SAL_CALL
Interceptor::getInterceptedURLs(  )
    throw (
        uno::RuntimeException
    )
{
    // now implemented as update

    return m_aInterceptedURL;
}

// XDispatchProvider

uno::Reference< frame::XDispatch > SAL_CALL
Interceptor::queryDispatch(
    const util::URL& URL,
    const ::rtl::OUString& TargetFrameName,
    sal_Int32 SearchFlags )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    if(URL.Complete == m_aInterceptedURL[0])
        return (frame::XDispatch*)this;
    else if(URL.Complete == m_aInterceptedURL[1])
        return (frame::XDispatch*)0   ;
    else if(URL.Complete == m_aInterceptedURL[2])
        return (frame::XDispatch*)this;
    else if(URL.Complete == m_aInterceptedURL[3])
        return (frame::XDispatch*)this;
    else if(URL.Complete == m_aInterceptedURL[4])
        return (frame::XDispatch*)this;
    else {
        if(m_xSlaveDispatchProvider.is())
            return m_xSlaveDispatchProvider->queryDispatch(
                URL,TargetFrameName,SearchFlags);
        else
            return uno::Reference<frame::XDispatch>(0);
    }
}

uno::Sequence< uno::Reference< frame::XDispatch > > SAL_CALL
Interceptor::queryDispatches(
    const uno::Sequence<frame::DispatchDescriptor >& Requests )
    throw (
        uno::RuntimeException
    )
{
    uno::Sequence< uno::Reference< frame::XDispatch > > aRet;
    osl::MutexGuard aGuard(m_aMutex);
    if(m_xSlaveDispatchProvider.is())
        aRet = m_xSlaveDispatchProvider->queryDispatches(Requests);
    else
        aRet.realloc(Requests.getLength());

    for(sal_Int32 i = 0; i < Requests.getLength(); ++i)
        if(m_aInterceptedURL[0] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;
        else if(m_aInterceptedURL[1] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) 0;
        else if(m_aInterceptedURL[2] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;
        else if(m_aInterceptedURL[3] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;
        else if(m_aInterceptedURL[4] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;

    return aRet;
}

//XDispatchProviderInterceptor

uno::Reference< frame::XDispatchProvider > SAL_CALL
Interceptor::getSlaveDispatchProvider(  )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    return m_xSlaveDispatchProvider;
}

void SAL_CALL
Interceptor::setSlaveDispatchProvider(
    const uno::Reference< frame::XDispatchProvider >& NewDispatchProvider )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    m_xSlaveDispatchProvider = NewDispatchProvider;
}

uno::Reference< frame::XDispatchProvider > SAL_CALL
Interceptor::getMasterDispatchProvider(  )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    return m_xMasterDispatchProvider;
}

void SAL_CALL
Interceptor::setMasterDispatchProvider(
    const uno::Reference< frame::XDispatchProvider >& NewSupplier )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    m_xMasterDispatchProvider = NewSupplier;
}
<commit_msg>#i2822#: typo<commit_after>/*************************************************************************
 *
 *  $RCSfile: intercept.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: mba $ $Date: 2003-04-04 12:12:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#include "intercept.hxx"
#ifndef _EMBEDDOC_HXX_
#include "embeddoc.hxx"
#endif
#ifndef _DOCHOLDER_HXX_
#include "docholder.hxx"
#endif

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

#define IUL 5

uno::Sequence<::rtl::OUString> Interceptor::m_aInterceptedURL(IUL);

struct equalOUString
{
    bool operator()(
        const rtl::OUString& rKey1,
        const rtl::OUString& rKey2 ) const
    {
        return !!( rKey1 == rKey2 );
    }
};

struct hashOUString
{
    size_t operator()( const rtl::OUString& rName ) const
    {
        return rName.hashCode();
    }
};

class StatusChangeListenerContainer
    : public ::cppu::OMultiTypeInterfaceContainerHelperVar<
rtl::OUString,hashOUString,equalOUString>
{
public:
    StatusChangeListenerContainer( ::osl::Mutex& aMutex )
        :  cppu::OMultiTypeInterfaceContainerHelperVar<
    rtl::OUString,hashOUString,equalOUString>(aMutex)
    {
    }
};

void SAL_CALL
Interceptor::addEventListener(
    const uno::Reference<lang::XEventListener >& Listener )
    throw( uno::RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( ! m_pDisposeEventListeners )
        m_pDisposeEventListeners =
            new cppu::OInterfaceContainerHelper( m_aMutex );

    m_pDisposeEventListeners->addInterface( Listener );
}

void SAL_CALL
Interceptor::removeEventListener(
    const uno::Reference< lang::XEventListener >& Listener )
    throw( uno::RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( m_pDisposeEventListeners )
        m_pDisposeEventListeners->removeInterface( Listener );
}

void SAL_CALL Interceptor::dispose()
{
    lang::EventObject aEvt;
    aEvt.Source = static_cast< frame::XDispatch* >( this );

    osl::MutexGuard aGuard(m_aMutex);

    if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
        m_pDisposeEventListeners->disposeAndClear( aEvt );

    if(m_pStatCL)
        m_pStatCL->disposeAndClear( aEvt );

    m_xSlaveDispatchProvider = 0;
    m_xMasterDispatchProvider = 0;
}

Interceptor::Interceptor(
    EmbedDocument_Impl* pOLEInterface,
    DocumentHolder* pDocH)
    : m_pOLEInterface(pOLEInterface),
      m_pDocH(pDocH),
      m_pStatCL(0),
      m_pDisposeEventListeners(0)
{
    m_aInterceptedURL[0] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:Save"));
    m_aInterceptedURL[1] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:SaveAll"));
    m_aInterceptedURL[2] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:CloseDoc"));
    m_aInterceptedURL[3] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:CloseWin"));
    m_aInterceptedURL[4] = rtl::OUString(
        RTL_CONSTASCII_USTRINGPARAM(".uno:CloseFrame"));
}

Interceptor::~Interceptor()
{
    if( m_pDisposeEventListeners )
        delete m_pDisposeEventListeners;

    if(m_pStatCL)
        delete m_pStatCL;

    m_pDocH->ClearInterceptor();
}

//XDispatch
void SAL_CALL
Interceptor::dispatch(
    const util::URL& URL,
    const uno::Sequence<
    beans::PropertyValue >& Arguments )
    throw (uno::RuntimeException)
{
    if(m_pOLEInterface)
        if(URL.Complete == m_aInterceptedURL[0])
            m_pOLEInterface->SaveObject();
        else if(URL.Complete == m_aInterceptedURL[2] ||
                URL.Complete == m_aInterceptedURL[3] ||
                URL.Complete == m_aInterceptedURL[4])
            m_pOLEInterface->Close(1);
}

void Interceptor::generateFeatureStateEvent()
{
    if(m_pStatCL)
    {
        for(int i = 0; i < IUL; ++i)
        {
            if( i == 1 )
                continue;

            cppu::OInterfaceContainerHelper* pICH =
                m_pStatCL->getContainer(m_aInterceptedURL[i]);
            uno::Sequence<uno::Reference<uno::XInterface> > aSeq;
            if(pICH)
                aSeq = pICH->getElements();
            if(!aSeq.getLength())
                continue;

            frame::FeatureStateEvent aStateEvent;
            aStateEvent.IsEnabled = sal_True;
            aStateEvent.Requery = sal_False;
            if(i == 0)
            {

                aStateEvent.FeatureURL.Complete = m_aInterceptedURL[0];
                aStateEvent.FeatureDescriptor = rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("Update"));
                aStateEvent.State <<= (rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("($1) ")) +
                                       m_pDocH->getTitle());

            }
            else
            {
                aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
                aStateEvent.FeatureDescriptor = rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
                aStateEvent.State <<= (rtl::OUString(
                    RTL_CONSTASCII_USTRINGPARAM("($2) ")) +
                                       m_pDocH->getTitle());

            }

            for(sal_Int32 k = 0; k < aSeq.getLength(); ++k)
            {
                uno::Reference<frame::XStatusListener>
                    Control(aSeq[k],uno::UNO_QUERY);
                if(Control.is())
                    Control->statusChanged(aStateEvent);

            }
        }
    }
}

void SAL_CALL
Interceptor::addStatusListener(
    const uno::Reference<
    frame::XStatusListener >& Control,
    const util::URL& URL )
    throw (
        uno::RuntimeException
    )
{
    if(!Control.is())
        return;

    if(URL.Complete == m_aInterceptedURL[0])
    {   // Save
        frame::FeatureStateEvent aStateEvent;
        aStateEvent.FeatureURL.Complete = m_aInterceptedURL[0];
        aStateEvent.FeatureDescriptor = rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("Update"));
        aStateEvent.IsEnabled = sal_True;
        aStateEvent.Requery = sal_False;
        aStateEvent.State <<= (rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("($1) ")) +
                               m_pDocH->getTitle());
        Control->statusChanged(aStateEvent);

        {
            osl::MutexGuard aGuard(m_aMutex);
            if(!m_pStatCL)
                m_pStatCL =
                    new StatusChangeListenerContainer(m_aMutex);
        }

        m_pStatCL->addInterface(URL.Complete,Control);
        return;
    }

    sal_Int32 i = 2;
    if(URL.Complete == m_aInterceptedURL[i] ||
       URL.Complete == m_aInterceptedURL[++i] ||
       URL.Complete == m_aInterceptedURL[++i] )
    {   // Close and return
        frame::FeatureStateEvent aStateEvent;
        aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
        aStateEvent.FeatureDescriptor = rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("Close and Return"));
        aStateEvent.IsEnabled = sal_True;
        aStateEvent.Requery = sal_False;
        aStateEvent.State <<= (rtl::OUString(
            RTL_CONSTASCII_USTRINGPARAM("($2) ")) +
                               m_pDocH->getTitle());
        Control->statusChanged(aStateEvent);

        {
            osl::MutexGuard aGuard(m_aMutex);
            if(!m_pStatCL)
                m_pStatCL =
                    new StatusChangeListenerContainer(m_aMutex);
        }

        m_pStatCL->addInterface(URL.Complete,Control);
        return;
    }
}

void SAL_CALL
Interceptor::removeStatusListener(
    const uno::Reference<
    frame::XStatusListener >& Control,
    const util::URL& URL )
    throw (
        uno::RuntimeException
    )
{
    if(!(Control.is() && m_pStatCL))
        return;
    else {
        m_pStatCL->removeInterface(URL.Complete,Control);
        return;
    }
}

//XInterceptorInfo
uno::Sequence< ::rtl::OUString >
SAL_CALL
Interceptor::getInterceptedURLs(  )
    throw (
        uno::RuntimeException
    )
{
    // now implemented as update

    return m_aInterceptedURL;
}

// XDispatchProvider

uno::Reference< frame::XDispatch > SAL_CALL
Interceptor::queryDispatch(
    const util::URL& URL,
    const ::rtl::OUString& TargetFrameName,
    sal_Int32 SearchFlags )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    if(URL.Complete == m_aInterceptedURL[0])
        return (frame::XDispatch*)this;
    else if(URL.Complete == m_aInterceptedURL[1])
        return (frame::XDispatch*)0   ;
    else if(URL.Complete == m_aInterceptedURL[2])
        return (frame::XDispatch*)this;
    else if(URL.Complete == m_aInterceptedURL[3])
        return (frame::XDispatch*)this;
    else if(URL.Complete == m_aInterceptedURL[4])
        return (frame::XDispatch*)this;
    else {
        if(m_xSlaveDispatchProvider.is())
            return m_xSlaveDispatchProvider->queryDispatch(
                URL,TargetFrameName,SearchFlags);
        else
            return uno::Reference<frame::XDispatch>(0);
    }
}

uno::Sequence< uno::Reference< frame::XDispatch > > SAL_CALL
Interceptor::queryDispatches(
    const uno::Sequence<frame::DispatchDescriptor >& Requests )
    throw (
        uno::RuntimeException
    )
{
    uno::Sequence< uno::Reference< frame::XDispatch > > aRet;
    osl::MutexGuard aGuard(m_aMutex);
    if(m_xSlaveDispatchProvider.is())
        aRet = m_xSlaveDispatchProvider->queryDispatches(Requests);
    else
        aRet.realloc(Requests.getLength());

    for(sal_Int32 i = 0; i < Requests.getLength(); ++i)
        if(m_aInterceptedURL[0] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;
        else if(m_aInterceptedURL[1] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) 0;
        else if(m_aInterceptedURL[2] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;
        else if(m_aInterceptedURL[3] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;
        else if(m_aInterceptedURL[4] == Requests[i].FeatureURL.Complete)
            aRet[i] = (frame::XDispatch*) this;

    return aRet;
}

//XDispatchProviderInterceptor

uno::Reference< frame::XDispatchProvider > SAL_CALL
Interceptor::getSlaveDispatchProvider(  )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    return m_xSlaveDispatchProvider;
}

void SAL_CALL
Interceptor::setSlaveDispatchProvider(
    const uno::Reference< frame::XDispatchProvider >& NewDispatchProvider )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    m_xSlaveDispatchProvider = NewDispatchProvider;
}

uno::Reference< frame::XDispatchProvider > SAL_CALL
Interceptor::getMasterDispatchProvider(  )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    return m_xMasterDispatchProvider;
}

void SAL_CALL
Interceptor::setMasterDispatchProvider(
    const uno::Reference< frame::XDispatchProvider >& NewSupplier )
    throw (
        uno::RuntimeException
    )
{
    osl::MutexGuard aGuard(m_aMutex);
    m_xMasterDispatchProvider = NewSupplier;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <chartsql/CSTableScan.h>
#include <chartsql/qtree/ColumnReferenceNode.h>
#include <chartsql/runtime/defaultruntime.h>
#include <chartsql/runtime/compile.h>
#include <fnord/inspect.h>

using namespace fnord;

namespace csql {

CSTableScan::CSTableScan(
    RefPtr<SequentialScanNode> stmt,
    cstable::CSTableReader&& cstable,
    Runtime* runtime) :
    cstable_(std::move(cstable)),
    colindex_(0),
    aggr_strategy_(stmt->aggregationStrategy()) {

  Set<String> column_names;
  for (const auto& slnode : stmt->selectList()) {
    findColumns(slnode->expression(), &column_names);
    column_names_.emplace_back(slnode->columnName());
  }

  for (const auto& col : column_names) {
    columns_.emplace(col, ColumnRef(cstable_.getColumnReader(col), colindex_++));
  }

  for (auto& slnode : stmt->selectList()) {
    resolveColumns(slnode->expression());
  }

  for (const auto& slnode : stmt->selectList()) {
    select_list_.emplace_back(
        findMaxRepetitionLevel(slnode->expression()),
        runtime->buildValueExpression(slnode->expression()),
        &scratch_);
  }

  auto where_expr = stmt->whereExpression();
  if (!where_expr.isEmpty()) {
    where_expr_ = runtime->buildValueExpression(where_expr.get());
  }
}

void CSTableScan::execute(
    ExecutionContext* context,
    Function<bool (int argc, const SValue* argv)> fn) {
  context->incrNumSubtasksTotal(1);
  scan(fn);
  context->incrNumSubtasksCompleted(1);
}

void CSTableScan::scan(
    Function<bool (int argc, const SValue* argv)> fn) {
  uint64_t select_level = 0;
  uint64_t fetch_level = 0;

  Vector<SValue> in_row(colindex_, SValue{});
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t num_records = 0;
  size_t total_records = cstable_.numRecords();
  while (num_records < total_records) {
    uint64_t next_level = 0;

    if (fetch_level == 0) {
      ++num_records;
    }

    for (auto& col : columns_) {
      auto nextr = col.second.reader->nextRepetitionLevel();

      if (nextr >= fetch_level) {
        auto& reader = col.second.reader;

        uint64_t r;
        uint64_t d;
        void* data;
        size_t size;
        reader->next(&r, &d, &data, &size);

        if (d < reader->maxDefinitionLevel()) {
          in_row[col.second.index] = SValue();
        } else {
          switch (col.second.reader->type()) {

            case msg::FieldType::STRING:
              in_row[col.second.index] =
                  SValue(SValue::StringType((char*) data, size));
              break;

            case msg::FieldType::UINT32:
            case msg::FieldType::UINT64:
              switch (size) {
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint32_t*) data)));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint64_t*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            case msg::FieldType::BOOLEAN:
              switch (size) {
                case sizeof(uint8_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint8_t*) data) > 0));
                  break;
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint32_t*) data) > 0));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint64_t*) data) > 0));
                  break;
                case 0:
                  in_row[col.second.index] = SValue(SValue::BoolType(false));
                  break;
              }
              break;

            case msg::FieldType::OBJECT:
              RAISE(kIllegalStateError);

          }
        }
      }

      next_level = std::max(
          next_level,
          col.second.reader->nextRepetitionLevel());
    }

    fetch_level = next_level;

    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(in_row.size(), in_row.data(), &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) { // where clause
      for (int i = 0; i < select_list_.size(); ++i) {
        if (select_list_[i].rep_level >= select_level) {
          select_list_[i].compiled->accumulate(
              &select_list_[i].instance,
              in_row.size(),
              in_row.data());
        }
      }

      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
          if (next_level != 0) {
            break;
          }

          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->result(
                &select_list_[i].instance,
                &out_row[i]);

            select_list_[i].compiled->reset(&select_list_[i].instance);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                in_row.size(),
                in_row.data(),
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

      }

      select_level = fetch_level;
    } else {
      select_level = std::min(select_level, fetch_level);
    }

    for (const auto& col : columns_) {
      if (col.second.reader->maxRepetitionLevel() >= select_level) {
        in_row[col.second.index] = SValue();
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::findColumns(
    RefPtr<ValueExpressionNode> expr,
    Set<String>* column_names) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    column_names->emplace(fieldref->fieldName());
  }

  for (const auto& e : expr->arguments()) {
    findColumns(e, column_names);
  }
}

void CSTableScan::resolveColumns(RefPtr<ValueExpressionNode> expr) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    fieldref->setColumnIndex(col->second.index);
  }

  for (const auto& e : expr->arguments()) {
    resolveColumns(e);
  }
}

uint64_t CSTableScan::findMaxRepetitionLevel(
    RefPtr<ValueExpressionNode> expr) const {
  uint64_t max_level = 0;

  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    auto col_level = col->second.reader->maxRepetitionLevel();
    if (col_level > max_level) {
      max_level = col_level;
    }
  }

  for (const auto& e : expr->arguments()) {
    auto e_level = findMaxRepetitionLevel(e);
    if (e_level > max_level) {
      max_level = e_level;
    }
  }

  return max_level;
}

Vector<String> CSTableScan::columnNames() const {
  return column_names_;
}

size_t CSTableScan::numColumns() const {
  return column_names_.size();
}

CSTableScan::ColumnRef::ColumnRef(
    RefPtr<cstable::ColumnReader> r,
    size_t i) :
    reader(r),
    index(i) {}

CSTableScan::ExpressionRef::ExpressionRef(
    size_t _rep_level,
    ScopedPtr<ValueExpression> _compiled,
    ScratchMemory* smem) :
    rep_level(_rep_level),
    compiled(std::move(_compiled)),
    instance(compiled->allocInstance(smem)) {}

CSTableScan::ExpressionRef::ExpressionRef(
    ExpressionRef&& other) :
    rep_level(other.rep_level),
    compiled(std::move(other.compiled)),
    instance(other.instance) {
  other.instance.scratch = nullptr;
}

CSTableScan::ExpressionRef::~ExpressionRef() {
  if (instance.scratch) {
    compiled->freeInstance(&instance);
  }
}

} // namespace csql
<commit_msg>resolve where expr columns<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <chartsql/CSTableScan.h>
#include <chartsql/qtree/ColumnReferenceNode.h>
#include <chartsql/runtime/defaultruntime.h>
#include <chartsql/runtime/compile.h>
#include <fnord/inspect.h>

using namespace fnord;

namespace csql {

CSTableScan::CSTableScan(
    RefPtr<SequentialScanNode> stmt,
    cstable::CSTableReader&& cstable,
    Runtime* runtime) :
    cstable_(std::move(cstable)),
    colindex_(0),
    aggr_strategy_(stmt->aggregationStrategy()) {
  Set<String> column_names;
  for (const auto& slnode : stmt->selectList()) {
    findColumns(slnode->expression(), &column_names);
    column_names_.emplace_back(slnode->columnName());
  }

  auto where_expr = stmt->whereExpression();
  if (!where_expr.isEmpty()) {
    findColumns(where_expr.get(), &column_names);
  }

  for (const auto& col : column_names) {
    columns_.emplace(col, ColumnRef(cstable_.getColumnReader(col), colindex_++));
  }

  for (auto& slnode : stmt->selectList()) {
    resolveColumns(slnode->expression());
  }

  for (const auto& slnode : stmt->selectList()) {
    select_list_.emplace_back(
        findMaxRepetitionLevel(slnode->expression()),
        runtime->buildValueExpression(slnode->expression()),
        &scratch_);
  }

  if (!where_expr.isEmpty()) {
    resolveColumns(where_expr.get());
    where_expr_ = runtime->buildValueExpression(where_expr.get());
  }
}

void CSTableScan::execute(
    ExecutionContext* context,
    Function<bool (int argc, const SValue* argv)> fn) {
  context->incrNumSubtasksTotal(1);
  scan(fn);
  context->incrNumSubtasksCompleted(1);
}

void CSTableScan::scan(
    Function<bool (int argc, const SValue* argv)> fn) {
  uint64_t select_level = 0;
  uint64_t fetch_level = 0;

  Vector<SValue> in_row(colindex_, SValue{});
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t num_records = 0;
  size_t total_records = cstable_.numRecords();
  while (num_records < total_records) {
    uint64_t next_level = 0;

    if (fetch_level == 0) {
      ++num_records;
    }

    for (auto& col : columns_) {
      auto nextr = col.second.reader->nextRepetitionLevel();

      if (nextr >= fetch_level) {
        auto& reader = col.second.reader;

        uint64_t r;
        uint64_t d;
        void* data;
        size_t size;
        reader->next(&r, &d, &data, &size);

        if (d < reader->maxDefinitionLevel()) {
          in_row[col.second.index] = SValue();
        } else {
          switch (col.second.reader->type()) {

            case msg::FieldType::STRING:
              in_row[col.second.index] =
                  SValue(SValue::StringType((char*) data, size));
              break;

            case msg::FieldType::UINT32:
            case msg::FieldType::UINT64:
              switch (size) {
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint32_t*) data)));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint64_t*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            case msg::FieldType::BOOLEAN:
              switch (size) {
                case sizeof(uint8_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint8_t*) data) > 0));
                  break;
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint32_t*) data) > 0));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint64_t*) data) > 0));
                  break;
                case 0:
                  in_row[col.second.index] = SValue(SValue::BoolType(false));
                  break;
              }
              break;

            case msg::FieldType::OBJECT:
              RAISE(kIllegalStateError);

          }
        }
      }

      next_level = std::max(
          next_level,
          col.second.reader->nextRepetitionLevel());
    }

    fetch_level = next_level;

    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(in_row.size(), in_row.data(), &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) { // where clause
      for (int i = 0; i < select_list_.size(); ++i) {
        if (select_list_[i].rep_level >= select_level) {
          select_list_[i].compiled->accumulate(
              &select_list_[i].instance,
              in_row.size(),
              in_row.data());
        }
      }

      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
          if (next_level != 0) {
            break;
          }

          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->result(
                &select_list_[i].instance,
                &out_row[i]);

            select_list_[i].compiled->reset(&select_list_[i].instance);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                in_row.size(),
                in_row.data(),
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

      }

      select_level = fetch_level;
    } else {
      select_level = std::min(select_level, fetch_level);
    }

    for (const auto& col : columns_) {
      if (col.second.reader->maxRepetitionLevel() >= select_level) {
        in_row[col.second.index] = SValue();
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::findColumns(
    RefPtr<ValueExpressionNode> expr,
    Set<String>* column_names) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    column_names->emplace(fieldref->fieldName());
  }

  for (const auto& e : expr->arguments()) {
    findColumns(e, column_names);
  }
}

void CSTableScan::resolveColumns(RefPtr<ValueExpressionNode> expr) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    fieldref->setColumnIndex(col->second.index);
  }

  for (const auto& e : expr->arguments()) {
    resolveColumns(e);
  }
}

uint64_t CSTableScan::findMaxRepetitionLevel(
    RefPtr<ValueExpressionNode> expr) const {
  uint64_t max_level = 0;

  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      RAISE(kIllegalStateError);
    }

    auto col_level = col->second.reader->maxRepetitionLevel();
    if (col_level > max_level) {
      max_level = col_level;
    }
  }

  for (const auto& e : expr->arguments()) {
    auto e_level = findMaxRepetitionLevel(e);
    if (e_level > max_level) {
      max_level = e_level;
    }
  }

  return max_level;
}

Vector<String> CSTableScan::columnNames() const {
  return column_names_;
}

size_t CSTableScan::numColumns() const {
  return column_names_.size();
}

CSTableScan::ColumnRef::ColumnRef(
    RefPtr<cstable::ColumnReader> r,
    size_t i) :
    reader(r),
    index(i) {}

CSTableScan::ExpressionRef::ExpressionRef(
    size_t _rep_level,
    ScopedPtr<ValueExpression> _compiled,
    ScratchMemory* smem) :
    rep_level(_rep_level),
    compiled(std::move(_compiled)),
    instance(compiled->allocInstance(smem)) {}

CSTableScan::ExpressionRef::ExpressionRef(
    ExpressionRef&& other) :
    rep_level(other.rep_level),
    compiled(std::move(other.compiled)),
    instance(other.instance) {
  other.instance.scratch = nullptr;
}

CSTableScan::ExpressionRef::~ExpressionRef() {
  if (instance.scratch) {
    compiled->freeInstance(&instance);
  }
}

} // namespace csql
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <chartsql/CSTableScan.h>
#include <chartsql/qtree/ColumnReferenceNode.h>
#include <chartsql/runtime/defaultruntime.h>
#include <chartsql/runtime/compile.h>
#include <stx/ieee754.h>

using namespace stx;

namespace csql {

CSTableScan::CSTableScan(
    RefPtr<SequentialScanNode> stmt,
    const String& cstable_filename,
    QueryBuilder* runtime) :
    stmt_(stmt),
    cstable_filename_(cstable_filename),
    runtime_(runtime),
    colindex_(0),
    aggr_strategy_(stmt_->aggregationStrategy()) {}

void CSTableScan::execute(
    ExecutionContext* context,
    Function<bool (int argc, const SValue* argv)> fn) {
  context->incrNumSubtasksTotal(1);

  Set<String> column_names;
  for (const auto& slnode : stmt_->selectList()) {
    findColumns(slnode->expression(), &column_names);
    column_names_.emplace_back(slnode->columnName());
  }

  auto where_expr = stmt_->whereExpression();
  if (!where_expr.isEmpty()) {
    findColumns(where_expr.get(), &column_names);
  }

  cstable::CSTableReader cstable(cstable_filename_);

  for (const auto& col : column_names) {
    if (cstable.hasColumn(col)) {
      columns_.emplace(
          col,
          ColumnRef(cstable.getColumnReader(col), colindex_++));
    }
  }

  for (auto& slnode : stmt_->selectList()) {
    resolveColumns(slnode->expression());
  }

  for (const auto& slnode : stmt_->selectList()) {
    select_list_.emplace_back(
        findMaxRepetitionLevel(slnode->expression()),
        runtime_->buildValueExpression(slnode->expression()),
        &scratch_);
  }

  if (!where_expr.isEmpty()) {
    resolveColumns(where_expr.get());
    where_expr_ = runtime_->buildValueExpression(where_expr.get());
  }

  if (columns_.empty()) {
    scanWithoutColumns(&cstable, fn);
  } else {
    scan(&cstable, fn);
  }

  context->incrNumSubtasksCompleted(1);
}

void CSTableScan::scan(
    cstable::CSTableReader* cstable,
    Function<bool (int argc, const SValue* argv)> fn) {
  uint64_t select_level = 0;
  uint64_t fetch_level = 0;

  Vector<SValue> in_row(colindex_, SValue{});
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t num_records = 0;
  size_t total_records = cstable->numRecords();
  while (num_records < total_records) {
    uint64_t next_level = 0;

    if (fetch_level == 0) {
      ++num_records;
    }

    for (auto& col : columns_) {
      auto nextr = col.second.reader->nextRepetitionLevel();

      if (nextr >= fetch_level) {
        auto& reader = col.second.reader;

        uint64_t r;
        uint64_t d;
        void* data;
        size_t size;
        reader->next(&r, &d, &data, &size);

        if (d < reader->maxDefinitionLevel()) {
          in_row[col.second.index] = SValue();
        } else {
          switch (col.second.reader->type()) {

            case msg::FieldType::STRING:
              in_row[col.second.index] =
                  SValue(SValue::StringType((char*) data, size));
              break;

            case msg::FieldType::UINT32:
            case msg::FieldType::UINT64:
              switch (size) {
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint32_t*) data)));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint64_t*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            case msg::FieldType::BOOLEAN:
              switch (size) {
                case sizeof(uint8_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint8_t*) data) > 0));
                  break;
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint32_t*) data) > 0));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint64_t*) data) > 0));
                  break;
                case 0:
                  in_row[col.second.index] = SValue(SValue::BoolType(false));
                  break;
              }
              break;

            case msg::FieldType::DOUBLE:
              switch (size) {
                case sizeof(double):
                  in_row[col.second.index] =
                      SValue(SValue::FloatType(*((double*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            default:
              RAISE(kIllegalStateError);

          }
        }
      }

      next_level = std::max(
          next_level,
          col.second.reader->nextRepetitionLevel());
    }

    fetch_level = next_level;

    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(in_row.size(), in_row.data(), &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      for (int i = 0; i < select_list_.size(); ++i) {
        if (select_list_[i].rep_level >= select_level) {
          select_list_[i].compiled->accumulate(
              &select_list_[i].instance,
              in_row.size(),
              in_row.data());
        }
      }

      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
          if (next_level != 0) {
            break;
          }

          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->result(
                &select_list_[i].instance,
                &out_row[i]);

            select_list_[i].compiled->reset(&select_list_[i].instance);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                in_row.size(),
                in_row.data(),
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

      }

      select_level = fetch_level;
    } else {
      select_level = std::min(select_level, fetch_level);
    }

    for (const auto& col : columns_) {
      if (col.second.reader->maxRepetitionLevel() >= select_level) {
        in_row[col.second.index] = SValue();
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::scanWithoutColumns(
    cstable::CSTableReader* cstable,
    Function<bool (int argc, const SValue* argv)> fn) {
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t total_records = cstable->numRecords();
  for (size_t i = 0; i < total_records; ++i) {
    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(0, nullptr, &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->accumulate(
                &select_list_[i].instance,
                0,
                nullptr);
          }
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                0,
                nullptr,
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }
          break;
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::findColumns(
    RefPtr<ValueExpressionNode> expr,
    Set<String>* column_names) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    column_names->emplace(fieldref->fieldName());
  }

  for (const auto& e : expr->arguments()) {
    findColumns(e, column_names);
  }
}

void CSTableScan::resolveColumns(RefPtr<ValueExpressionNode> expr) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      fieldref->setColumnIndex(size_t(-1));
    } else {
      fieldref->setColumnIndex(col->second.index);
    }
  }

  for (const auto& e : expr->arguments()) {
    resolveColumns(e);
  }
}

uint64_t CSTableScan::findMaxRepetitionLevel(
    RefPtr<ValueExpressionNode> expr) const {
  uint64_t max_level = 0;

  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
      if (col != columns_.end()) {
      auto col_level = col->second.reader->maxRepetitionLevel();
      if (col_level > max_level) {
        max_level = col_level;
      }
    }
  }

  for (const auto& e : expr->arguments()) {
    auto e_level = findMaxRepetitionLevel(e);
    if (e_level > max_level) {
      max_level = e_level;
    }
  }

  return max_level;
}

Vector<String> CSTableScan::columnNames() const {
  return column_names_;
}

size_t CSTableScan::numColumns() const {
  return column_names_.size();
}

CSTableScan::ColumnRef::ColumnRef(
    RefPtr<cstable::ColumnReader> r,
    size_t i) :
    reader(r),
    index(i) {}

CSTableScan::ExpressionRef::ExpressionRef(
    size_t _rep_level,
    ScopedPtr<ValueExpression> _compiled,
    ScratchMemory* smem) :
    rep_level(_rep_level),
    compiled(std::move(_compiled)),
    instance(compiled->allocInstance(smem)) {}

CSTableScan::ExpressionRef::ExpressionRef(
    ExpressionRef&& other) :
    rep_level(other.rep_level),
    compiled(std::move(other.compiled)),
    instance(other.instance) {
  other.instance.scratch = nullptr;
}

CSTableScan::ExpressionRef::~ExpressionRef() {
  if (instance.scratch) {
    compiled->freeInstance(&instance);
  }
}

} // namespace csql
<commit_msg>logging<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <chartsql/CSTableScan.h>
#include <chartsql/qtree/ColumnReferenceNode.h>
#include <chartsql/runtime/defaultruntime.h>
#include <chartsql/runtime/compile.h>
#include <stx/ieee754.h>
#include <stx/logging.h>

using namespace stx;

namespace csql {

CSTableScan::CSTableScan(
    RefPtr<SequentialScanNode> stmt,
    const String& cstable_filename,
    QueryBuilder* runtime) :
    stmt_(stmt),
    cstable_filename_(cstable_filename),
    runtime_(runtime),
    colindex_(0),
    aggr_strategy_(stmt_->aggregationStrategy()) {}

void CSTableScan::execute(
    ExecutionContext* context,
    Function<bool (int argc, const SValue* argv)> fn) {
  context->incrNumSubtasksTotal(1);

  logDebug("sql", "Scanning cstable: $0", cstable_filename_);

  Set<String> column_names;
  for (const auto& slnode : stmt_->selectList()) {
    findColumns(slnode->expression(), &column_names);
    column_names_.emplace_back(slnode->columnName());
  }

  auto where_expr = stmt_->whereExpression();
  if (!where_expr.isEmpty()) {
    findColumns(where_expr.get(), &column_names);
  }

  cstable::CSTableReader cstable(cstable_filename_);

  for (const auto& col : column_names) {
    if (cstable.hasColumn(col)) {
      columns_.emplace(
          col,
          ColumnRef(cstable.getColumnReader(col), colindex_++));
    }
  }

  for (auto& slnode : stmt_->selectList()) {
    resolveColumns(slnode->expression());
  }

  for (const auto& slnode : stmt_->selectList()) {
    select_list_.emplace_back(
        findMaxRepetitionLevel(slnode->expression()),
        runtime_->buildValueExpression(slnode->expression()),
        &scratch_);
  }

  if (!where_expr.isEmpty()) {
    resolveColumns(where_expr.get());
    where_expr_ = runtime_->buildValueExpression(where_expr.get());
  }

  if (columns_.empty()) {
    scanWithoutColumns(&cstable, fn);
  } else {
    scan(&cstable, fn);
  }

  context->incrNumSubtasksCompleted(1);
}

void CSTableScan::scan(
    cstable::CSTableReader* cstable,
    Function<bool (int argc, const SValue* argv)> fn) {
  uint64_t select_level = 0;
  uint64_t fetch_level = 0;

  Vector<SValue> in_row(colindex_, SValue{});
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t num_records = 0;
  size_t total_records = cstable->numRecords();
  while (num_records < total_records) {
    uint64_t next_level = 0;

    if (fetch_level == 0) {
      ++num_records;
    }

    for (auto& col : columns_) {
      auto nextr = col.second.reader->nextRepetitionLevel();

      if (nextr >= fetch_level) {
        auto& reader = col.second.reader;

        uint64_t r;
        uint64_t d;
        void* data;
        size_t size;
        reader->next(&r, &d, &data, &size);

        if (d < reader->maxDefinitionLevel()) {
          in_row[col.second.index] = SValue();
        } else {
          switch (col.second.reader->type()) {

            case msg::FieldType::STRING:
              in_row[col.second.index] =
                  SValue(SValue::StringType((char*) data, size));
              break;

            case msg::FieldType::UINT32:
            case msg::FieldType::UINT64:
              switch (size) {
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint32_t*) data)));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::IntegerType(*((uint64_t*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            case msg::FieldType::BOOLEAN:
              switch (size) {
                case sizeof(uint8_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint8_t*) data) > 0));
                  break;
                case sizeof(uint32_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint32_t*) data) > 0));
                  break;
                case sizeof(uint64_t):
                  in_row[col.second.index] =
                      SValue(SValue::BoolType(*((uint64_t*) data) > 0));
                  break;
                case 0:
                  in_row[col.second.index] = SValue(SValue::BoolType(false));
                  break;
              }
              break;

            case msg::FieldType::DOUBLE:
              switch (size) {
                case sizeof(double):
                  in_row[col.second.index] =
                      SValue(SValue::FloatType(*((double*) data)));
                  break;
                case 0:
                  in_row[col.second.index] = SValue();
                  break;
              }
              break;

            default:
              RAISE(kIllegalStateError);

          }
        }
      }

      next_level = std::max(
          next_level,
          col.second.reader->nextRepetitionLevel());
    }

    fetch_level = next_level;

    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(in_row.size(), in_row.data(), &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      for (int i = 0; i < select_list_.size(); ++i) {
        if (select_list_[i].rep_level >= select_level) {
          select_list_[i].compiled->accumulate(
              &select_list_[i].instance,
              in_row.size(),
              in_row.data());
        }
      }

      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
          if (next_level != 0) {
            break;
          }

          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->result(
                &select_list_[i].instance,
                &out_row[i]);

            select_list_[i].compiled->reset(&select_list_[i].instance);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                in_row.size(),
                in_row.data(),
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }

          break;

      }

      select_level = fetch_level;
    } else {
      select_level = std::min(select_level, fetch_level);
    }

    for (const auto& col : columns_) {
      if (col.second.reader->maxRepetitionLevel() >= select_level) {
        in_row[col.second.index] = SValue();
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::scanWithoutColumns(
    cstable::CSTableReader* cstable,
    Function<bool (int argc, const SValue* argv)> fn) {
  Vector<SValue> out_row(select_list_.size(), SValue{});

  size_t total_records = cstable->numRecords();
  for (size_t i = 0; i < total_records; ++i) {
    bool where_pred = true;
    if (where_expr_.get() != nullptr) {
      SValue where_tmp;
      where_expr_->evaluate(0, nullptr, &where_tmp);
      where_pred = where_tmp.getBoolWithConversion();
    }

    if (where_pred) {
      switch (aggr_strategy_) {

        case AggregationStrategy::AGGREGATE_ALL:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->accumulate(
                &select_list_[i].instance,
                0,
                nullptr);
          }
          break;

        case AggregationStrategy::AGGREGATE_WITHIN_RECORD:
        case AggregationStrategy::NO_AGGREGATION:
          for (int i = 0; i < select_list_.size(); ++i) {
            select_list_[i].compiled->evaluate(
                0,
                nullptr,
                &out_row[i]);
          }

          if (!fn(out_row.size(), out_row.data())) {
            return;
          }
          break;
      }
    }
  }

  switch (aggr_strategy_) {
    case AggregationStrategy::AGGREGATE_ALL:
      for (int i = 0; i < select_list_.size(); ++i) {
        select_list_[i].compiled->result(
            &select_list_[i].instance,
            &out_row[i]);
      }

      fn(out_row.size(), out_row.data());
      break;

    default:
      break;

  }
}

void CSTableScan::findColumns(
    RefPtr<ValueExpressionNode> expr,
    Set<String>* column_names) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    column_names->emplace(fieldref->fieldName());
  }

  for (const auto& e : expr->arguments()) {
    findColumns(e, column_names);
  }
}

void CSTableScan::resolveColumns(RefPtr<ValueExpressionNode> expr) const {
  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
    if (col == columns_.end()) {
      fieldref->setColumnIndex(size_t(-1));
    } else {
      fieldref->setColumnIndex(col->second.index);
    }
  }

  for (const auto& e : expr->arguments()) {
    resolveColumns(e);
  }
}

uint64_t CSTableScan::findMaxRepetitionLevel(
    RefPtr<ValueExpressionNode> expr) const {
  uint64_t max_level = 0;

  auto fieldref = dynamic_cast<ColumnReferenceNode*>(expr.get());
  if (fieldref != nullptr) {
    auto col = columns_.find(fieldref->fieldName());
      if (col != columns_.end()) {
      auto col_level = col->second.reader->maxRepetitionLevel();
      if (col_level > max_level) {
        max_level = col_level;
      }
    }
  }

  for (const auto& e : expr->arguments()) {
    auto e_level = findMaxRepetitionLevel(e);
    if (e_level > max_level) {
      max_level = e_level;
    }
  }

  return max_level;
}

Vector<String> CSTableScan::columnNames() const {
  return column_names_;
}

size_t CSTableScan::numColumns() const {
  return column_names_.size();
}

CSTableScan::ColumnRef::ColumnRef(
    RefPtr<cstable::ColumnReader> r,
    size_t i) :
    reader(r),
    index(i) {}

CSTableScan::ExpressionRef::ExpressionRef(
    size_t _rep_level,
    ScopedPtr<ValueExpression> _compiled,
    ScratchMemory* smem) :
    rep_level(_rep_level),
    compiled(std::move(_compiled)),
    instance(compiled->allocInstance(smem)) {}

CSTableScan::ExpressionRef::ExpressionRef(
    ExpressionRef&& other) :
    rep_level(other.rep_level),
    compiled(std::move(other.compiled)),
    instance(other.instance) {
  other.instance.scratch = nullptr;
}

CSTableScan::ExpressionRef::~ExpressionRef() {
  if (instance.scratch) {
    compiled->freeInstance(&instance);
  }
}

} // namespace csql
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014—2016 David Wicks, sansumbrella.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once
#include <vector>
#include "Phrase.hpp"
#include "UnitBezier.h"
#include "TimeType.h"

namespace choreograph
{

class Curve
{
public:
  enum Type {
    Bezier,
    Hold,
    Linear
  };
  float solve(float t) const;
  void  setType(Type type) { _type = type; }
  void  hold() { _type = Hold; }
  BezierInterpolant& bezier() { _type = Bezier; return _bezier; }
private:
  Type              _type = Linear;
  BezierInterpolant _bezier;
};

float Curve::solve(float t) const
{
  switch (_type) {
    case Bezier:
      return _bezier.solve(t);
    break;
    case Hold:
      return 0.0f;
    break;
    case Linear:
      return t;
    break;
    default:
      return t;
    break;
  }
}

///
/// Simple channel concept with bezier interpolation between keys.
/// Goals:
/// - Easy serialization
/// - Easy to create graphical manipulation tools.
/// - Flexible enough for doing an AfterEffects-style
///
template <typename T>
class Channel
{
public:
  struct Key {
    Key(T value, Time time):
      value(value),
      time(time)
    {}
    T    value;
    Time time;
  };

  Channel() = default;

  /// Return the value of the channel at a given time.
  T value(Time at_time) const;
  /// Return the interpolated value between two keys.
  /// If you keep track of keys yourself, this is faster.
  T interpolatedValue(size_t curve_index, Time at_time) const;

  /// Returns the index of the curve for the current time.
  /// The curve lies between two keys.
  size_t index(Time at_time) const;

  /// Append a key to the list of keys, positioned at \offset time after the previous key.
  Channel& appendKeyAfter(T value, Time offset) {
    if (! _keys.empty()) {
      _curves.emplace_back();
    }
    _keys.emplace_back(value, duration() + offset);
    return *this;
  }
  /// Insert a key at the given time.
  Channel& insertKey(T value, Time at_time);

  Time     duration() const { return _keys.empty() ? 0 : _keys.back().time; }

private:
  std::vector<Key>   _keys;
  // may make polymorphic in future (like phrases are). Basically just an ease fn.
  // Compare std::function<float (float)> for max flexibility against custom class.
  std::vector<Curve> _curves;
};

#pragma mark - Channel Template Implementation

template <typename T>
size_t Channel<T>::index(Time at_time) const {
  if( at_time <= 0 ) {
    return 0;
  }
  else if ( at_time >= this->duration() ) {
    return _curves.size() - 1;
  }

  for (auto i = 0; i < _keys.size() - 1; i += 1) {
    auto &a = _keys[i], &b = _keys[i + 1];
    if (a.time <= at_time && b.time >= at_time) {
      return i;
    }
  }
  return _curves.size() - 1;
}

template <typename T>
T Channel<T>::value(Time at_time) const {
  if (at_time >= duration()) {
    return _keys.back().value;
  }
  else if (at_time <= 0.0) {
    return _keys.front().value;
  }

  return interpolatedValue(index(at_time), at_time);
}

template <typename T>
T Channel<T>::interpolatedValue(size_t curve_index, Time at_time) const {
  auto &a = _keys[curve_index];
  auto &b = _keys[curve_index + 1];
  auto &c = _curves[curve_index];

  auto x = (at_time - a.time) / (b.time - a.time);
  auto t = c.solve(x);
  return lerpT(a.value, b.value, t);
}

template <typename T>
Channel<T>& Channel<T>::insertKey(T value, Time at_time) {
  if (_keys.empty()) {
    _keys.emplace_back(value, at_time);
  }
  else {
    _keys.insert(_keys.begin() + (index(at_time) + 1), {value, at_time});
  }

  return *this;
}

} // namepsace choreograph
<commit_msg>Notes on goals and grouping possibilities.<commit_after>/*
 * Copyright (c) 2014—2016 David Wicks, sansumbrella.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once
#include <vector>
#include "Phrase.hpp"
#include "UnitBezier.h"
#include "TimeType.h"

namespace choreograph
{

class Curve
{
public:
  enum Type {
    Bezier,
    Hold,
    Linear
  };
  float solve(float t) const;
  void  setType(Type type) { _type = type; }
  void  hold() { _type = Hold; }
  BezierInterpolant& bezier() { _type = Bezier; return _bezier; }
private:
  Type              _type = Linear;
  BezierInterpolant _bezier;
};

float Curve::solve(float t) const
{
  switch (_type) {
    case Bezier:
      return _bezier.solve(t);
    break;
    case Hold:
      return 0.0f;
    break;
    case Linear:
      return t;
    break;
    default:
      return t;
    break;
  }
}

///
/// Simple channel concept with bezier interpolation between keys.
/// Goals:
/// - Easy serialization
/// - Easy to create graphical manipulation tools.
///   - Support direct manipulation of animation data.
///   - Avoid deeply nested information. Flat hierarchy.
/// - Flexible enough to create an AfterEffects-style timeline.
///
/// Good for animating single values, like floats or quaternions.
/// For vector types, use a channel per component (and maybe add a group type to associate them).
/// Grouping type could be a manipulator/animator type class that reads/writes multiple channels.
///
template <typename T>
class Channel
{
public:
  struct Key {
    Key(T value, Time time):
      value(value),
      time(time)
    {}
    T    value;
    Time time;
  };

  Channel() = default;

  /// Return the value of the channel at a given time.
  T value(Time at_time) const;
  /// Return the interpolated value between two keys.
  /// If you keep track of keys yourself, this is faster.
  T interpolatedValue(size_t curve_index, Time at_time) const;

  /// Returns the index of the curve for the current time.
  /// The curve lies between two keys.
  size_t index(Time at_time) const;

  /// Append a key to the list of keys, positioned at \offset time after the previous key.
  Channel& appendKeyAfter(T value, Time offset) {
    if (! _keys.empty()) {
      _curves.emplace_back();
    }
    _keys.emplace_back(value, duration() + offset);
    return *this;
  }
  /// Insert a key at the given time.
  Channel& insertKey(T value, Time at_time);

  Time     duration() const { return _keys.empty() ? 0 : _keys.back().time; }

private:
  std::vector<Key>   _keys;
  // may make polymorphic in future (like phrases are). Basically just an ease fn.
  // Compare std::function<float (float)> for max flexibility against custom class.
  std::vector<Curve> _curves;
};

#pragma mark - Channel Template Implementation

template <typename T>
size_t Channel<T>::index(Time at_time) const {
  if( at_time <= 0 ) {
    return 0;
  }
  else if ( at_time >= this->duration() ) {
    return _curves.size() - 1;
  }

  for (auto i = 0; i < _keys.size() - 1; i += 1) {
    auto &a = _keys[i], &b = _keys[i + 1];
    if (a.time <= at_time && b.time >= at_time) {
      return i;
    }
  }
  return _curves.size() - 1;
}

template <typename T>
T Channel<T>::value(Time at_time) const {
  if (at_time >= duration()) {
    return _keys.back().value;
  }
  else if (at_time <= 0.0) {
    return _keys.front().value;
  }

  return interpolatedValue(index(at_time), at_time);
}

template <typename T>
T Channel<T>::interpolatedValue(size_t curve_index, Time at_time) const {
  auto &a = _keys[curve_index];
  auto &b = _keys[curve_index + 1];
  auto &c = _curves[curve_index];

  auto x = (at_time - a.time) / (b.time - a.time);
  auto t = c.solve(x);
  return lerpT(a.value, b.value, t);
}

template <typename T>
Channel<T>& Channel<T>::insertKey(T value, Time at_time) {
  if (_keys.empty()) {
    _keys.emplace_back(value, at_time);
  }
  else {
    _keys.insert(_keys.begin() + (index(at_time) + 1), {value, at_time});
  }

  return *this;
}

} // namepsace choreograph
<|endoftext|>


<commit_before>/*
 *  SMTP.cpp
 *  OpenLieroX
 *
 *  Created by Albert Zeyer on 19.10.09.
 *  Code under LGPL.
 *
 */

#include "Networking.h"
#include "SMTP.h"
#include "Debug.h"
#include "Timer.h"

struct SmtpClient::Handler {
	NetworkSocket sock;
};

static bool SmtpClient_wait(NetworkSocket& sock, const std::string& expectedstart) {
	char c = 0;
	int r = 0;
	std::string line;
	AbsTime startTime = GetTime();
	while((r = sock.Read(&c, 1)) >= 0) {
		if(r == 0) {
			if(GetTime() - startTime >= TimeDiff(float(10.0))) {
				errors << "SMTP: timeout while waiting for " << expectedstart << endl;
				return false;
			}
			SDL_Delay(10);
			continue;
		}

		if(c == '\n') break;
		line += c;
	}
	if(r < 0) {
		errors << "SMTP: error while waiting for " << expectedstart << endl;
		return false;
	}

	if(!subStrEqual(line, expectedstart, expectedstart.size())) {
		errors << "SMTP: expected was " << expectedstart << " but we got '" << line << "'" << endl;
		return false;
	}

	return true;
}

static bool SmtpClient_write(NetworkSocket& sock, const std::string& line) {
	if(sock.Write(line + "\n") < int(line.size() + 1)) {
		errors << "SMTP: error while writing " << line << endl;
		return false;
	}
	return true;
}

static bool SmtpClient_writeAndWait(NetworkSocket& sock, const std::string& line, const std::string& expectedanswer) {
	if(!SmtpClient_write(sock, line)) return false;
	return SmtpClient_wait(sock, expectedanswer);
}

bool SmtpClient::connect() {
	if(intern) reset();
	intern = new Handler();

	NetworkAddr addr;
	AbsTime dnsRequestTime = GetTime();
	if(!GetNetAddrFromNameAsync(host, addr)) {
		errors << "SMTP: Error while starting name resolution for " << host << endl;
		return false;
	}

	while(!IsNetAddrValid(addr)) {
		if((GetTime() - dnsRequestTime).seconds() >= DNS_TIMEOUT) {
			errors << "SMTP: DNS timeout while resolving " << host << endl;
			return false;
		}
		SDL_Delay(10);
	}

	std::string host_addr;
	NetAddrToString(addr, host_addr);
	//notes << "SMTP: resolved " << host << " to " << host_addr << endl;

	if(!intern->sock.OpenReliable(0)) {
		errors << "SMTP: error while opening socket" << endl;
		return false;
	}

	AbsTime connectingTime = GetTime();
	if(!intern->sock.Connect(addr)) {
		errors << "SMTP: error while trying to connect to " << host << endl;
		return false;
	}

	while(!intern->sock.isReady()) {
		if((GetTime() - connectingTime).seconds() >= 10) {
			errors << "SMTP: connect timeout to " << host << endl;
			return false;
		}
		SDL_Delay(10);
	}

	if(!SmtpClient_wait(intern->sock, "220 ")) return false;
	if(!SmtpClient_writeAndWait(intern->sock, "MAIL FROM:" + mailfrom, "250 ")) return false;
	for(std::list<std::string>::iterator i = mailrcpts.begin(); i != mailrcpts.end(); ++i)
		if(!SmtpClient_writeAndWait(intern->sock, "RCPT TO:" + *i, "250 ")) return false;
	if(!SmtpClient_writeAndWait(intern->sock, "DATA", "354 ")) return false;
	if(!SmtpClient_write(intern->sock, "From: " + mailfrom)) return false;
	for(std::list<std::string>::iterator i = mailrcpts.begin(); i != mailrcpts.end(); ++i)
		if(!SmtpClient_write(intern->sock, "To: " + *i)) return false;
	if(!SmtpClient_write(intern->sock, "Subject: " + subject)) return false;
	for(std::list<std::string>::iterator i = headers.begin(); i != headers.end(); ++i)
		if(!SmtpClient_write(intern->sock, *i)) return false;
	if(!SmtpClient_write(intern->sock, "")) return false;

	return true;
}

bool SmtpClient::addText(const std::string& txt) {
	if(!intern || !intern->sock.isReady()) {
		errors << "SMTP addtext: socket not ready" << endl;
		return false;
	}

	if(txt == "")
		return SmtpClient_write(intern->sock, "");

	std::string line;
	for(std::string::const_iterator i = txt.begin(); i != txt.end(); ++i) {
		if(*i == '\n') {
			if(line != "" && line[0] == '.') line = " " + line; // to not end the mail
			if(!SmtpClient_write(intern->sock, line)) return false;
			line = "";
			continue;
		}

		line += *i;
	}

	if(line != "") {
		if(line[0] == '.') line = " " + line; // to not end the mail
		if(!SmtpClient_write(intern->sock, line)) return false;
	}

	return true;
}

bool SmtpClient::close() {
	if(!SmtpClient_writeAndWait(intern->sock, ".", "250 ")) return false;
	if(!SmtpClient_writeAndWait(intern->sock, "QUIT", "221 ")) return false;
	intern->sock.Close();
	return true;
}

void SmtpClient::reset() {
	if(intern) {
		delete intern;
		intern = NULL;
	}
}

<commit_msg>removed too short timeout (just wait until there is something; if there is an error, it would break anyway); correct write on socket<commit_after>/*
 *  SMTP.cpp
 *  OpenLieroX
 *
 *  Created by Albert Zeyer on 19.10.09.
 *  Code under LGPL.
 *
 */

#include "Networking.h"
#include "SMTP.h"
#include "Debug.h"
#include "Timer.h"

struct SmtpClient::Handler {
	NetworkSocket sock;
};

static bool SmtpClient_wait(NetworkSocket& sock, const std::string& expectedstart) {
	char c = 0;
	int r = 0;
	std::string line;
	AbsTime startTime = GetTime();
	while((r = sock.Read(&c, 1)) >= 0) {
		if(r == 0) {
			SDL_Delay(10);
			continue;
		}

		if(c == '\n') break;
		line += c;
	}
	if(r < 0) {
		errors << "SMTP: error while waiting for " << expectedstart << endl;
		return false;
	}

	if(!subStrEqual(line, expectedstart, expectedstart.size())) {
		errors << "SMTP: expected was " << expectedstart << " but we got '" << line << "'" << endl;
		return false;
	}

	return true;
}

static bool writeOnSocket(NetworkSocket& sock, std::string buf) {
	while(buf.size() > 0) {
		int ret = sock.Write(buf);
		if(ret < 0) return false;
		buf.erase(0, ret);
	}
	return true;
}

static bool SmtpClient_write(NetworkSocket& sock, const std::string& line) {
	if(!writeOnSocket(sock, line + "\n")) {
		errors << "SMTP: error while writing " << line << endl;
		return false;
	}
	return true;
}

static bool SmtpClient_writeAndWait(NetworkSocket& sock, const std::string& line, const std::string& expectedanswer) {
	if(!SmtpClient_write(sock, line)) return false;
	return SmtpClient_wait(sock, expectedanswer);
}

bool SmtpClient::connect() {
	if(intern) reset();
	intern = new Handler();

	NetworkAddr addr;
	AbsTime dnsRequestTime = GetTime();
	if(!GetNetAddrFromNameAsync(host, addr)) {
		errors << "SMTP: Error while starting name resolution for " << host << endl;
		return false;
	}

	while(!IsNetAddrValid(addr)) {
		if((GetTime() - dnsRequestTime).seconds() >= DNS_TIMEOUT) {
			errors << "SMTP: DNS timeout while resolving " << host << endl;
			return false;
		}
		SDL_Delay(10);
	}

	std::string host_addr;
	NetAddrToString(addr, host_addr);
	//notes << "SMTP: resolved " << host << " to " << host_addr << endl;

	if(!intern->sock.OpenReliable(0)) {
		errors << "SMTP: error while opening socket" << endl;
		return false;
	}

	AbsTime connectingTime = GetTime();
	if(!intern->sock.Connect(addr)) {
		errors << "SMTP: error while trying to connect to " << host << endl;
		return false;
	}

	while(!intern->sock.isReady()) {
		if((GetTime() - connectingTime).seconds() >= 10) {
			errors << "SMTP: connect timeout to " << host << endl;
			return false;
		}
		SDL_Delay(10);
	}

	if(!SmtpClient_wait(intern->sock, "220 ")) return false;
	if(!SmtpClient_writeAndWait(intern->sock, "MAIL FROM:" + mailfrom, "250 ")) return false;
	for(std::list<std::string>::iterator i = mailrcpts.begin(); i != mailrcpts.end(); ++i)
		if(!SmtpClient_writeAndWait(intern->sock, "RCPT TO:" + *i, "250 ")) return false;
	if(!SmtpClient_writeAndWait(intern->sock, "DATA", "354 ")) return false;
	if(!SmtpClient_write(intern->sock, "From: " + mailfrom)) return false;
	for(std::list<std::string>::iterator i = mailrcpts.begin(); i != mailrcpts.end(); ++i)
		if(!SmtpClient_write(intern->sock, "To: " + *i)) return false;
	if(!SmtpClient_write(intern->sock, "Subject: " + subject)) return false;
	for(std::list<std::string>::iterator i = headers.begin(); i != headers.end(); ++i)
		if(!SmtpClient_write(intern->sock, *i)) return false;
	if(!SmtpClient_write(intern->sock, "")) return false;

	return true;
}

bool SmtpClient::addText(const std::string& txt) {
	if(!intern || !intern->sock.isReady()) {
		errors << "SMTP addtext: socket not ready" << endl;
		return false;
	}

	if(txt == "")
		return SmtpClient_write(intern->sock, "");

	std::string line;
	for(std::string::const_iterator i = txt.begin(); i != txt.end(); ++i) {
		if(*i == '\n') {
			if(line != "" && line[0] == '.') line = " " + line; // to not end the mail
			if(!SmtpClient_write(intern->sock, line)) return false;
			line = "";
			continue;
		}

		line += *i;
	}

	if(line != "") {
		if(line[0] == '.') line = " " + line; // to not end the mail
		if(!SmtpClient_write(intern->sock, line)) return false;
	}

	return true;
}

bool SmtpClient::close() {
	if(!SmtpClient_writeAndWait(intern->sock, ".", "250 ")) return false;
	if(!SmtpClient_writeAndWait(intern->sock, "QUIT", "221 ")) return false;
	intern->sock.Close();
	return true;
}

void SmtpClient::reset() {
	if(intern) {
		delete intern;
		intern = NULL;
	}
}

<|endoftext|>