<commit_before>/*************************************************************************
 *
 *  $RCSfile: propertysetbase.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 11:38:13 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#include "propertysetbase.hxx"

#include <cppuhelper/typeprovider.hxx>  // for getImplementationId()

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/uno/Reference.hxx>

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include <vector>

using com::sun::star::uno::Any;
using com::sun::star::uno::Type;
using com::sun::star::uno::Sequence;
using com::sun::star::uno::Reference;
using com::sun::star::uno::Exception;
using com::sun::star::uno::RuntimeException;
using com::sun::star::lang::IllegalArgumentException;
using com::sun::star::beans::Property;
using com::sun::star::beans::XPropertySetInfo;

oslInterlockedCount SAL_CALL PropertyAccessorBase::acquire()
{
    return ++m_refCount;
}

oslInterlockedCount SAL_CALL PropertyAccessorBase::release()
{
    if ( --m_refCount == 0 )
    {
        delete this;
        return 0;
    }
    return m_refCount;
}

PropertySetBase::PropertySetBase( )
    :m_pProperties( NULL )
{
}

PropertySetBase::~PropertySetBase( )
{
    DELETEZ( m_pProperties );
}

cppu::IPropertyArrayHelper& SAL_CALL PropertySetBase::getInfoHelper()
{
    if ( !m_pProperties )
    {
        DBG_ASSERT( !m_aProperties.empty(), "PropertySetBase::getInfoHelper: no registered properties!" );
        m_pProperties = new cppu::OPropertyArrayHelper( m_aProperties.begin(), m_aProperties.size(), sal_False );
    }
    return *m_pProperties;
}

Reference< XPropertySetInfo > SAL_CALL PropertySetBase::getPropertySetInfo(  ) throw(RuntimeException)
{
    return cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
}

void PropertySetBase::registerProperty( const Property& rProperty,
    const ::rtl::Reference< PropertyAccessorBase >& rAccessor )
{
    DBG_ASSERT( rAccessor.get(), "PropertySetBase::registerProperty: invalid property accessor, this will crash!" );
    m_aAccessors.insert( PropertyAccessors::value_type( rProperty.Handle, rAccessor ) );

    DBG_ASSERT( ( rAccessor->isWriteable() == true )
                == ( ( rProperty.Attributes & com::sun::star::beans::PropertyAttribute::READONLY ) == 0 ),
        "PropertySetBase::registerProperty: inconsistence!" );

    m_aProperties.push_back( rProperty );
}

void PropertySetBase::notifyAndCachePropertyValue( sal_Int32 nHandle )
{
    ::osl::ClearableMutexGuard aGuard( GetMutex() );

    PropertyValueCache::iterator aPos = m_aCache.find( nHandle );
    if ( aPos == m_aCache.end() )
    {   // method has never before been invoked for this property
        try
        {
            // determine the type of this property
            ::cppu::IPropertyArrayHelper& rPropertyMetaData = getInfoHelper();
            ::rtl::OUString sPropName;
            OSL_VERIFY( rPropertyMetaData.fillPropertyMembersByHandle( &sPropName, NULL, nHandle ) );
            Property aProperty = rPropertyMetaData.getPropertyByName( sPropName );
            // default construct a value of this type
            Any aEmptyValue( NULL, aProperty.Type );
            // insert into the cache
            aPos = m_aCache.insert( PropertyValueCache::value_type( nHandle, aEmptyValue ) ).first;
        }
        catch( Exception& )
        {
            DBG_ERROR( "PropertySetBase::notifyAndCachePropertyValue: this is not expected to fail!" );
        }
    }
    Any aOldValue = aPos->second;
    // determine the current value
    Any aNewValue;
    getFastPropertyValue( aNewValue, nHandle );
    // remember the old value
    aPos->second = aNewValue;

    aGuard.clear();
    if ( aNewValue != aOldValue )
        firePropertyChange( nHandle, aNewValue, aOldValue );
}

void PropertySetBase::initializePropertyValueCache( sal_Int32 nHandle )
{
    Any aCurrentValue;
    getFastPropertyValue( aCurrentValue, nHandle );

#if OSL_DEBUG_LEVEL > 0
    ::std::pair< PropertyValueCache::iterator, bool > aInsertResult =
#endif
    m_aCache.insert( PropertyValueCache::value_type( nHandle, aCurrentValue ) );
    DBG_ASSERT( aInsertResult.second, "PropertySetBase::initializePropertyValueCache: already cached a value for this property!" );
}

PropertyAccessorBase& PropertySetBase::locatePropertyHandler( sal_Int32 nHandle ) const
{
    PropertyAccessors::const_iterator aPropertyPos = m_aAccessors.find( nHandle );
    DBG_ASSERT( aPropertyPos != m_aAccessors.end() && aPropertyPos->second.get(),
        "PropertySetBase::locatePropertyHandler: accessor map is corrupted!" );
        // neither should this be called for handles where there is no accessor, nor should a
        // NULL accssor be in the map
    return *aPropertyPos->second;
}

sal_Bool SAL_CALL PropertySetBase::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle,
    const Any& rValue )
    throw (IllegalArgumentException)
{
    PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
    if ( !rAccessor.approveValue( rValue ) )
        throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );

    rAccessor.getValue( rOldValue );
    if ( rOldValue != rValue )
    {
        rConvertedValue = rValue;   // no conversion at all
        return sal_True;
    }
    return sal_False;
}

void SAL_CALL PropertySetBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
    throw (Exception)
{
    PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
    rAccessor.setValue( rValue );
}

void SAL_CALL PropertySetBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
{
    PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
    rAccessor.getValue( rValue );
}
<commit_msg>INTEGRATION: CWS cmcfixes11 (1.3.46); FILE MERGED 2005/07/14 15:37:18 cmc 1.3.46.1: #i51974# update system stl debugging<commit_after>/*************************************************************************
 *
 *  $RCSfile: propertysetbase.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2005-07-18 08:42:35 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#include "propertysetbase.hxx"

#include <cppuhelper/typeprovider.hxx>  // for getImplementationId()

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/uno/Reference.hxx>

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include <vector>

using com::sun::star::uno::Any;
using com::sun::star::uno::Type;
using com::sun::star::uno::Sequence;
using com::sun::star::uno::Reference;
using com::sun::star::uno::Exception;
using com::sun::star::uno::RuntimeException;
using com::sun::star::lang::IllegalArgumentException;
using com::sun::star::beans::Property;
using com::sun::star::beans::XPropertySetInfo;

oslInterlockedCount SAL_CALL PropertyAccessorBase::acquire()
{
    return ++m_refCount;
}

oslInterlockedCount SAL_CALL PropertyAccessorBase::release()
{
    if ( --m_refCount == 0 )
    {
        delete this;
        return 0;
    }
    return m_refCount;
}

PropertySetBase::PropertySetBase( )
    :m_pProperties( NULL )
{
}

PropertySetBase::~PropertySetBase( )
{
    DELETEZ( m_pProperties );
}

cppu::IPropertyArrayHelper& SAL_CALL PropertySetBase::getInfoHelper()
{
    if ( !m_pProperties )
    {
        DBG_ASSERT( !m_aProperties.empty(), "PropertySetBase::getInfoHelper: no registered properties!" );
        m_pProperties = new cppu::OPropertyArrayHelper( &m_aProperties[0], m_aProperties.size(), sal_False );
    }
    return *m_pProperties;
}

Reference< XPropertySetInfo > SAL_CALL PropertySetBase::getPropertySetInfo(  ) throw(RuntimeException)
{
    return cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() );
}

void PropertySetBase::registerProperty( const Property& rProperty,
    const ::rtl::Reference< PropertyAccessorBase >& rAccessor )
{
    DBG_ASSERT( rAccessor.get(), "PropertySetBase::registerProperty: invalid property accessor, this will crash!" );
    m_aAccessors.insert( PropertyAccessors::value_type( rProperty.Handle, rAccessor ) );

    DBG_ASSERT( ( rAccessor->isWriteable() == true )
                == ( ( rProperty.Attributes & com::sun::star::beans::PropertyAttribute::READONLY ) == 0 ),
        "PropertySetBase::registerProperty: inconsistence!" );

    m_aProperties.push_back( rProperty );
}

void PropertySetBase::notifyAndCachePropertyValue( sal_Int32 nHandle )
{
    ::osl::ClearableMutexGuard aGuard( GetMutex() );

    PropertyValueCache::iterator aPos = m_aCache.find( nHandle );
    if ( aPos == m_aCache.end() )
    {   // method has never before been invoked for this property
        try
        {
            // determine the type of this property
            ::cppu::IPropertyArrayHelper& rPropertyMetaData = getInfoHelper();
            ::rtl::OUString sPropName;
            OSL_VERIFY( rPropertyMetaData.fillPropertyMembersByHandle( &sPropName, NULL, nHandle ) );
            Property aProperty = rPropertyMetaData.getPropertyByName( sPropName );
            // default construct a value of this type
            Any aEmptyValue( NULL, aProperty.Type );
            // insert into the cache
            aPos = m_aCache.insert( PropertyValueCache::value_type( nHandle, aEmptyValue ) ).first;
        }
        catch( Exception& )
        {
            DBG_ERROR( "PropertySetBase::notifyAndCachePropertyValue: this is not expected to fail!" );
        }
    }
    Any aOldValue = aPos->second;
    // determine the current value
    Any aNewValue;
    getFastPropertyValue( aNewValue, nHandle );
    // remember the old value
    aPos->second = aNewValue;

    aGuard.clear();
    if ( aNewValue != aOldValue )
        firePropertyChange( nHandle, aNewValue, aOldValue );
}

void PropertySetBase::initializePropertyValueCache( sal_Int32 nHandle )
{
    Any aCurrentValue;
    getFastPropertyValue( aCurrentValue, nHandle );

#if OSL_DEBUG_LEVEL > 0
    ::std::pair< PropertyValueCache::iterator, bool > aInsertResult =
#endif
    m_aCache.insert( PropertyValueCache::value_type( nHandle, aCurrentValue ) );
    DBG_ASSERT( aInsertResult.second, "PropertySetBase::initializePropertyValueCache: already cached a value for this property!" );
}

PropertyAccessorBase& PropertySetBase::locatePropertyHandler( sal_Int32 nHandle ) const
{
    PropertyAccessors::const_iterator aPropertyPos = m_aAccessors.find( nHandle );
    DBG_ASSERT( aPropertyPos != m_aAccessors.end() && aPropertyPos->second.get(),
        "PropertySetBase::locatePropertyHandler: accessor map is corrupted!" );
        // neither should this be called for handles where there is no accessor, nor should a
        // NULL accssor be in the map
    return *aPropertyPos->second;
}

sal_Bool SAL_CALL PropertySetBase::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle,
    const Any& rValue )
    throw (IllegalArgumentException)
{
    PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
    if ( !rAccessor.approveValue( rValue ) )
        throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );

    rAccessor.getValue( rOldValue );
    if ( rOldValue != rValue )
    {
        rConvertedValue = rValue;   // no conversion at all
        return sal_True;
    }
    return sal_False;
}

void SAL_CALL PropertySetBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
    throw (Exception)
{
    PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
    rAccessor.setValue( rValue );
}

void SAL_CALL PropertySetBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
{
    PropertyAccessorBase& rAccessor = locatePropertyHandler( nHandle );
    rAccessor.getValue( rValue );
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: writeguard.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 11:02:28 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
#define __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_THREADHELP_INONCOPYABLE_H_
#include <threadhelp/inoncopyable.h>
#endif

#ifndef __FRAMEWORK_THREADHELP_IRWLOCK_H_
#include <threadhelp/irwlock.h>
#endif

//#ifndef __FRAMEWORK_THREADHELP_THREADHELPBASE_HXX_
//#include <threadhelp/threadhelpbase.hxx>
//#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  other includes
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//  const
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  declarations
//_________________________________________________________________________________________________________________

/*-************************************************************************************************************//**
    @short          implement a guard to set write locks
    @descr          This guard should be used to set a lock for reading AND writing object internal member.
                    We never need a own mutex to safe our internal member access - because
                    a guard is used as function-local member only. There exist no multithreaded access to it realy ...

    @attention      a) To prevent us against wrong using, the default ctor, copy ctor and the =operator are maked private!
                    b) Use interface "IRWLock" of set LockHelper only - because we must support a finer granularity of locking.
                       Interface "IMutex" should be used by easier guard implementations ... like "ResetableGuard"!

    @implements     -
    @base           INonCopyable

    @devstatus      ready to use
*//*-*************************************************************************************************************/
class WriteGuard : private INonCopyable
{
    //-------------------------------------------------------------------------------------------------------------
    //  public methods
    //-------------------------------------------------------------------------------------------------------------
    public:

        /*-****************************************************************************************************//**
            @short      ctor
            @descr      These ctors initialize the guard with a reference to used lock member of object to protect.
                        Null isn't allowed as value!

            @seealso    -

            @param      "pLock" ,reference to used lock member of object to protect
            @param      "rLock" ,reference to used lock member of object to protect
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline WriteGuard( IRWLock* pLock )
            :   m_pLock ( pLock     )
            ,   m_eMode ( E_NOLOCK  )
        {
            lock();
        }

        //*********************************************************************************************************
        inline WriteGuard( IRWLock& rLock )
            :   m_pLock ( &rLock    )
            ,   m_eMode ( E_NOLOCK  )
        {
            lock();
        }

        /*-****************************************************************************************************//**
            @short      dtor
            @descr      We unlock the used lock member automaticly if user forget it.

            @seealso    -

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline ~WriteGuard()
        {
            unlock();
        }

        /*-****************************************************************************************************//**
            @short      set write lock
            @descr      Call this method to set the write lock. The call will block till all current threads are synchronized!

            @seealso    method unlock()

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline void lock()
        {
            switch( m_eMode )
            {
                case E_NOLOCK       :   {
                                            // Acquire write access and set return state.
                                            // Mode is set later if it was successful!
                                            m_pLock->acquireWriteAccess();
                                            m_eMode = E_WRITELOCK;
                                        }
                                        break;
                case E_READLOCK     :   {
                                            // User has downgrade to read access before!
                                            // We must release it before we can set a new write access!
                                            m_pLock->releaseReadAccess();
                                            m_pLock->acquireWriteAccess();
                                            m_eMode = E_WRITELOCK;
                                        }
                                        break;
                default:                break; // nothing to do
            }
        }

        /*-****************************************************************************************************//**
            @short      unset write lock
            @descr      Call this method to unlock the rw-lock temp.!
                        Normaly we do it at dtor automaticly for you ...

            @seealso    method lock()

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline void unlock()
        {
            switch( m_eMode )
            {
                case E_READLOCK     :   {
                                            // User has downgraded to a read lock before!
                                            // => There isn't realy a write lock ...
                                            m_pLock->releaseReadAccess();
                                            m_eMode = E_NOLOCK;
                                        }
                                        break;
                case E_WRITELOCK    :   {
                                            m_pLock->releaseWriteAccess();
                                            m_eMode = E_NOLOCK;
                                        }
                                        break;
                default:                break; // nothing to do
            }
        }

        /*-****************************************************************************************************//**
            @short      downgrade write access to read access without new blocking!
            @descr      If this write lock is set you can change it to a "read lock".
                        An "upgrade" is the same like new calling "lock()"!

            @seealso    -

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline void downgrade()
        {
            if( m_eMode == E_WRITELOCK )
            {
                m_pLock->downgradeWriteAccess();
                m_eMode = E_READLOCK;
            }
        }

        /*-****************************************************************************************************//**
            @short      return internal states
            @descr      For user they dont know what they are doing ...

            @seealso    -

            @param      -
            @return     Current set lock mode.

            @onerror    No error should occure.
        *//*-*****************************************************************************************************/
        inline ELockMode getMode() const
        {
            return m_eMode;
        }

    //-------------------------------------------------------------------------------------------------------------
    //  private methods
    //-------------------------------------------------------------------------------------------------------------
    private:

        /*-****************************************************************************************************//**
            @short      disable using of these functions!
            @descr      It's not allowed to use this methods. Different problem can occure otherwise.
                        Thats why we disable it by make it private.

            @seealso    other ctor

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        WriteGuard();

    //-------------------------------------------------------------------------------------------------------------
    //  private member
    //-------------------------------------------------------------------------------------------------------------
    private:

        IRWLock*    m_pLock ;   /// reference to lock-member of protected object
        ELockMode   m_eMode ;   /// protection against multiple lock calls without unlock and difference between supported lock modi

};      //  class WriteGuard

}       //  namespace framework

#endif  //  #ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
<commit_msg>INTEGRATION: CWS changefileheader (1.6.318); FILE MERGED 2008/04/01 10:57:55 thb 1.6.318.2: #i85898# Stripping all external header guards 2008/03/28 15:34:53 rt 1.6.318.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: writeguard.hxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
#define __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#include <threadhelp/inoncopyable.h>
#include <threadhelp/irwlock.h>

//#ifndef __FRAMEWORK_THREADHELP_THREADHELPBASE_HXX_
//#include <threadhelp/threadhelpbase.hxx>
//#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  other includes
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//  const
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  declarations
//_________________________________________________________________________________________________________________

/*-************************************************************************************************************//**
    @short          implement a guard to set write locks
    @descr          This guard should be used to set a lock for reading AND writing object internal member.
                    We never need a own mutex to safe our internal member access - because
                    a guard is used as function-local member only. There exist no multithreaded access to it realy ...

    @attention      a) To prevent us against wrong using, the default ctor, copy ctor and the =operator are maked private!
                    b) Use interface "IRWLock" of set LockHelper only - because we must support a finer granularity of locking.
                       Interface "IMutex" should be used by easier guard implementations ... like "ResetableGuard"!

    @implements     -
    @base           INonCopyable

    @devstatus      ready to use
*//*-*************************************************************************************************************/
class WriteGuard : private INonCopyable
{
    //-------------------------------------------------------------------------------------------------------------
    //  public methods
    //-------------------------------------------------------------------------------------------------------------
    public:

        /*-****************************************************************************************************//**
            @short      ctor
            @descr      These ctors initialize the guard with a reference to used lock member of object to protect.
                        Null isn't allowed as value!

            @seealso    -

            @param      "pLock" ,reference to used lock member of object to protect
            @param      "rLock" ,reference to used lock member of object to protect
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline WriteGuard( IRWLock* pLock )
            :   m_pLock ( pLock     )
            ,   m_eMode ( E_NOLOCK  )
        {
            lock();
        }

        //*********************************************************************************************************
        inline WriteGuard( IRWLock& rLock )
            :   m_pLock ( &rLock    )
            ,   m_eMode ( E_NOLOCK  )
        {
            lock();
        }

        /*-****************************************************************************************************//**
            @short      dtor
            @descr      We unlock the used lock member automaticly if user forget it.

            @seealso    -

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline ~WriteGuard()
        {
            unlock();
        }

        /*-****************************************************************************************************//**
            @short      set write lock
            @descr      Call this method to set the write lock. The call will block till all current threads are synchronized!

            @seealso    method unlock()

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline void lock()
        {
            switch( m_eMode )
            {
                case E_NOLOCK       :   {
                                            // Acquire write access and set return state.
                                            // Mode is set later if it was successful!
                                            m_pLock->acquireWriteAccess();
                                            m_eMode = E_WRITELOCK;
                                        }
                                        break;
                case E_READLOCK     :   {
                                            // User has downgrade to read access before!
                                            // We must release it before we can set a new write access!
                                            m_pLock->releaseReadAccess();
                                            m_pLock->acquireWriteAccess();
                                            m_eMode = E_WRITELOCK;
                                        }
                                        break;
                default:                break; // nothing to do
            }
        }

        /*-****************************************************************************************************//**
            @short      unset write lock
            @descr      Call this method to unlock the rw-lock temp.!
                        Normaly we do it at dtor automaticly for you ...

            @seealso    method lock()

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline void unlock()
        {
            switch( m_eMode )
            {
                case E_READLOCK     :   {
                                            // User has downgraded to a read lock before!
                                            // => There isn't realy a write lock ...
                                            m_pLock->releaseReadAccess();
                                            m_eMode = E_NOLOCK;
                                        }
                                        break;
                case E_WRITELOCK    :   {
                                            m_pLock->releaseWriteAccess();
                                            m_eMode = E_NOLOCK;
                                        }
                                        break;
                default:                break; // nothing to do
            }
        }

        /*-****************************************************************************************************//**
            @short      downgrade write access to read access without new blocking!
            @descr      If this write lock is set you can change it to a "read lock".
                        An "upgrade" is the same like new calling "lock()"!

            @seealso    -

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        inline void downgrade()
        {
            if( m_eMode == E_WRITELOCK )
            {
                m_pLock->downgradeWriteAccess();
                m_eMode = E_READLOCK;
            }
        }

        /*-****************************************************************************************************//**
            @short      return internal states
            @descr      For user they dont know what they are doing ...

            @seealso    -

            @param      -
            @return     Current set lock mode.

            @onerror    No error should occure.
        *//*-*****************************************************************************************************/
        inline ELockMode getMode() const
        {
            return m_eMode;
        }

    //-------------------------------------------------------------------------------------------------------------
    //  private methods
    //-------------------------------------------------------------------------------------------------------------
    private:

        /*-****************************************************************************************************//**
            @short      disable using of these functions!
            @descr      It's not allowed to use this methods. Different problem can occure otherwise.
                        Thats why we disable it by make it private.

            @seealso    other ctor

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/
        WriteGuard();

    //-------------------------------------------------------------------------------------------------------------
    //  private member
    //-------------------------------------------------------------------------------------------------------------
    private:

        IRWLock*    m_pLock ;   /// reference to lock-member of protected object
        ELockMode   m_eMode ;   /// protection against multiple lock calls without unlock and difference between supported lock modi

};      //  class WriteGuard

}       //  namespace framework

#endif  //  #ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
<|endoftext|>


<commit_before>#include <atomic>
#include "spdlog/async.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "logger.hpp"
#include "conf/conf.hpp"

#define LOGGER_FACTORY_UNINITIALIZED	(0)
#define LOGGER_FACTORY_INITIALIZING	(1)
#define LOGGER_FACTORY_INITIALIZED	(2)

std::atomic<uint32_t> LoggerFactory::_initialize_state = LOGGER_FACTORY_UNINITIALIZED;
std::shared_ptr<spdlog::logger> LoggerFactory::_default_logger;

std::shared_ptr<spdlog::logger> LoggerFactory::_create_logger(
    const std::string &logger_name,
    spdlog::level::level_enum log_level) {
    std::vector<spdlog::sink_ptr> log_sinks;
    log_sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
        logger_name + ".log",1L<<20, 3));
    log_sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
    std::shared_ptr<spdlog::logger> log = std::make_shared<spdlog::async_logger>(
        logger_name,
        log_sinks.begin(),
        log_sinks.end(),
        spdlog::thread_pool(),
        spdlog::async_overflow_policy::block);
    spdlog::register_logger(log);
    log->set_pattern("[%H:%M:%S.%f] [%n] [Thread %t] [%^%l%$] %v");
    log->set_level(log_level);
    return log;
}

// re-entrant and idempotent initializer.
void LoggerFactory::_initialize() {
    // static initialization
    uint32_t expected = LOGGER_FACTORY_UNINITIALIZED;
    if (_initialize_state.compare_exchange_strong(
        expected,LOGGER_FACTORY_INITIALIZING,std::memory_order_acq_rel)){
        // 1 - initialize the thread pool
        spdlog::init_thread_pool(1L<<20, 1); // 1MB buffer, 1 thread
        // 2 - initialize the default Logger
        std::string default_logger_name = derecho::getConfString(CONF_LOGGER_DEFAULT_LOG_NAME);
        std::string default_log_level = derecho::getConfString(CONF_LOGGER_DEFAULT_LOG_LEVEL);
        _default_logger = _create_logger(default_logger_name,
            spdlog::level::from_str(default_log_level));
        // 3 - change state to initialized
        _initialize_state.store(LOGGER_FACTORY_INITIALIZED,std::memory_order_acq_rel);
        auto start_ms = std::chrono::duration_cast<std::chrono::microseconds>(
            std::chrono::high_resolution_clock::now().time_since_epoch());
        _default_logger->debug("Program start time (microseconds): {}", start_ms.count());
    }
    // make sure initialization finished by concurrent callers
    while (_initialize_state.load(std::memory_order_acquire)!=LOGGER_FACTORY_UNINITIALIZED) {
    }
}

std::shared_ptr<spdlog::logger> LoggerFactory::createLogger(
    const std::string &logger_name,
    spdlog::level::level_enum log_level) {
    _initialize();
    return _create_logger(logger_name,log_level);
}

std::shared_ptr<spdlog::logger>& LoggerFactory::getDefaultLogger() {
    _initialize();
    return _default_logger;
}
<commit_msg>minor bugfix.<commit_after>#include <atomic>
#include "spdlog/async.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "logger.hpp"
#include "conf/conf.hpp"

#define LOGGER_FACTORY_UNINITIALIZED	(0)
#define LOGGER_FACTORY_INITIALIZING	(1)
#define LOGGER_FACTORY_INITIALIZED	(2)

std::atomic<uint32_t> LoggerFactory::_initialize_state = LOGGER_FACTORY_UNINITIALIZED;
std::shared_ptr<spdlog::logger> LoggerFactory::_default_logger;

std::shared_ptr<spdlog::logger> LoggerFactory::_create_logger(
    const std::string &logger_name,
    spdlog::level::level_enum log_level) {
    std::vector<spdlog::sink_ptr> log_sinks;
    log_sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
        logger_name + ".log",1L<<20, 3));
    log_sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
    std::shared_ptr<spdlog::logger> log = std::make_shared<spdlog::async_logger>(
        logger_name,
        log_sinks.begin(),
        log_sinks.end(),
        spdlog::thread_pool(),
        spdlog::async_overflow_policy::block);
    spdlog::register_logger(log);
    log->set_pattern("[%H:%M:%S.%f] [%n] [Thread %t] [%^%l%$] %v");
    log->set_level(log_level);
    return log;
}

// re-entrant and idempotent initializer.
void LoggerFactory::_initialize() {
    // static initialization
    uint32_t expected = LOGGER_FACTORY_UNINITIALIZED;
    if (_initialize_state.compare_exchange_strong(
        expected,LOGGER_FACTORY_INITIALIZING,std::memory_order_acq_rel)){
        // 1 - initialize the thread pool
        spdlog::init_thread_pool(1L<<20, 1); // 1MB buffer, 1 thread
        // 2 - initialize the default Logger
        std::string default_logger_name = derecho::getConfString(CONF_LOGGER_DEFAULT_LOG_NAME);
        std::string default_log_level = derecho::getConfString(CONF_LOGGER_DEFAULT_LOG_LEVEL);
        _default_logger = _create_logger(default_logger_name,
            spdlog::level::from_str(default_log_level));
        // 3 - change state to initialized
        _initialize_state.store(LOGGER_FACTORY_INITIALIZED,std::memory_order_acq_rel);
        auto start_ms = std::chrono::duration_cast<std::chrono::microseconds>(
            std::chrono::high_resolution_clock::now().time_since_epoch());
        _default_logger->debug("Program start time (microseconds): {}", start_ms.count());
    }
    // make sure initialization finished by concurrent callers
    while (_initialize_state.load(std::memory_order_acquire)!=LOGGER_FACTORY_INITIALIZED) {
    }
}

std::shared_ptr<spdlog::logger> LoggerFactory::createLogger(
    const std::string &logger_name,
    spdlog::level::level_enum log_level) {
    _initialize();
    return _create_logger(logger_name,log_level);
}

std::shared_ptr<spdlog::logger>& LoggerFactory::getDefaultLogger() {
    _initialize();
    return _default_logger;
}
<|endoftext|>


<commit_before>//===-- RecordSerialization.cpp -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Utilities for serializing and deserializing CodeView records.
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"

using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;

/// Reinterpret a byte array as an array of characters. Does not interpret as
/// a C string, as StringRef has several helpers (split) that make that easy.
StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
  return StringRef(reinterpret_cast<const char *>(LeafData.data()),
                   LeafData.size());
}

StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
  return getBytesAsCharacters(LeafData).split('\0').first;
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) {
  // Used to avoid overload ambiguity on APInt construtor.
  bool FalseVal = false;
  if (Data.size() < 2)
    return std::make_error_code(std::errc::illegal_byte_sequence);
  uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
  Data = Data.drop_front(2);
  if (Short < LF_NUMERIC) {
    Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
                 /*isUnsigned=*/true);
    return std::error_code();
  }
  switch (Short) {
  case LF_CHAR:
    Num = APSInt(APInt(/*numBits=*/8,
                       *reinterpret_cast<const int8_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(1);
    return std::error_code();
  case LF_SHORT:
    Num = APSInt(APInt(/*numBits=*/16,
                       *reinterpret_cast<const little16_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(2);
    return std::error_code();
  case LF_USHORT:
    Num = APSInt(APInt(/*numBits=*/16,
                       *reinterpret_cast<const ulittle16_t *>(Data.data()),
                       /*isSigned=*/false),
                 /*isUnsigned=*/true);
    Data = Data.drop_front(2);
    return std::error_code();
  case LF_LONG:
    Num = APSInt(APInt(/*numBits=*/32,
                       *reinterpret_cast<const little32_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(4);
    return std::error_code();
  case LF_ULONG:
    Num = APSInt(APInt(/*numBits=*/32,
                       *reinterpret_cast<const ulittle32_t *>(Data.data()),
                       /*isSigned=*/FalseVal),
                 /*isUnsigned=*/true);
    Data = Data.drop_front(4);
    return std::error_code();
  case LF_QUADWORD:
    Num = APSInt(APInt(/*numBits=*/64,
                       *reinterpret_cast<const little64_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(8);
    return std::error_code();
  case LF_UQUADWORD:
    Num = APSInt(APInt(/*numBits=*/64,
                       *reinterpret_cast<const ulittle64_t *>(Data.data()),
                       /*isSigned=*/false),
                 /*isUnsigned=*/true);
    Data = Data.drop_front(8);
    return std::error_code();
  }
  return std::make_error_code(std::errc::illegal_byte_sequence);
}

std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) {
  ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
  auto EC = consume(Bytes, Num);
  Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
  return EC;
}

/// Decode a numeric leaf value that is known to be a uint64_t.
std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data,
                                                uint64_t &Num) {
  APSInt N;
  if (auto EC = consume(Data, N))
    return EC;
  if (N.isSigned() || !N.isIntN(64))
    return std::make_error_code(std::errc::illegal_byte_sequence);
  Num = N.getLimitedValue();
  return std::error_code();
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
                                        uint32_t &Item) {
  const support::ulittle32_t *IntPtr;
  if (auto EC = consumeObject(Data, IntPtr))
    return EC;
  Item = *IntPtr;
  return std::error_code();
}

std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
  ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
  auto EC = consume(Bytes, Item);
  Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
  return EC;
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
                                        int32_t &Item) {
  const support::little32_t *IntPtr;
  if (auto EC = consumeObject(Data, IntPtr))
    return EC;
  Item = *IntPtr;
  return std::error_code();
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
                                        StringRef &Item) {
  if (Data.empty())
    return std::make_error_code(std::errc::illegal_byte_sequence);

  StringRef Rest;
  std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0');
  // We expect this to be null terminated.  If it was not, it is an error.
  if (Data.size() == Item.size())
    return std::make_error_code(std::errc::illegal_byte_sequence);

  Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
  return std::error_code();
}
<commit_msg>Make sure data is available before dereferencing it<commit_after>//===-- RecordSerialization.cpp -------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Utilities for serializing and deserializing CodeView records.
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"

using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;

/// Reinterpret a byte array as an array of characters. Does not interpret as
/// a C string, as StringRef has several helpers (split) that make that easy.
StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
  return StringRef(reinterpret_cast<const char *>(LeafData.data()),
                   LeafData.size());
}

StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
  return getBytesAsCharacters(LeafData).split('\0').first;
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) {
  // Used to avoid overload ambiguity on APInt construtor.
  bool FalseVal = false;
  if (Data.size() < 2)
    return std::make_error_code(std::errc::illegal_byte_sequence);
  uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
  Data = Data.drop_front(2);
  if (Short < LF_NUMERIC) {
    Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
                 /*isUnsigned=*/true);
    return std::error_code();
  }
  switch (Short) {
  case LF_CHAR:
    if (Data.size() < 1)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/8,
                       *reinterpret_cast<const int8_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(1);
    return std::error_code();
  case LF_SHORT:
    if (Data.size() < 2)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/16,
                       *reinterpret_cast<const little16_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(2);
    return std::error_code();
  case LF_USHORT:
    if (Data.size() < 2)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/16,
                       *reinterpret_cast<const ulittle16_t *>(Data.data()),
                       /*isSigned=*/false),
                 /*isUnsigned=*/true);
    Data = Data.drop_front(2);
    return std::error_code();
  case LF_LONG:
    if (Data.size() < 4)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/32,
                       *reinterpret_cast<const little32_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(4);
    return std::error_code();
  case LF_ULONG:
    if (Data.size() < 4)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/32,
                       *reinterpret_cast<const ulittle32_t *>(Data.data()),
                       /*isSigned=*/FalseVal),
                 /*isUnsigned=*/true);
    Data = Data.drop_front(4);
    return std::error_code();
  case LF_QUADWORD:
    if (Data.size() < 8)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/64,
                       *reinterpret_cast<const little64_t *>(Data.data()),
                       /*isSigned=*/true),
                 /*isUnsigned=*/false);
    Data = Data.drop_front(8);
    return std::error_code();
  case LF_UQUADWORD:
    if (Data.size() < 8)
      return std::make_error_code(std::errc::illegal_byte_sequence);
    Num = APSInt(APInt(/*numBits=*/64,
                       *reinterpret_cast<const ulittle64_t *>(Data.data()),
                       /*isSigned=*/false),
                 /*isUnsigned=*/true);
    Data = Data.drop_front(8);
    return std::error_code();
  }
  return std::make_error_code(std::errc::illegal_byte_sequence);
}

std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) {
  ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
  auto EC = consume(Bytes, Num);
  Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
  return EC;
}

/// Decode a numeric leaf value that is known to be a uint64_t.
std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data,
                                                uint64_t &Num) {
  APSInt N;
  if (auto EC = consume(Data, N))
    return EC;
  if (N.isSigned() || !N.isIntN(64))
    return std::make_error_code(std::errc::illegal_byte_sequence);
  Num = N.getLimitedValue();
  return std::error_code();
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
                                        uint32_t &Item) {
  const support::ulittle32_t *IntPtr;
  if (auto EC = consumeObject(Data, IntPtr))
    return EC;
  Item = *IntPtr;
  return std::error_code();
}

std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
  ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
  auto EC = consume(Bytes, Item);
  Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
  return EC;
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
                                        int32_t &Item) {
  const support::little32_t *IntPtr;
  if (auto EC = consumeObject(Data, IntPtr))
    return EC;
  Item = *IntPtr;
  return std::error_code();
}

std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
                                        StringRef &Item) {
  if (Data.empty())
    return std::make_error_code(std::errc::illegal_byte_sequence);

  StringRef Rest;
  std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0');
  // We expect this to be null terminated.  If it was not, it is an error.
  if (Data.size() == Item.size())
    return std::make_error_code(std::errc::illegal_byte_sequence);

  Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
  return std::error_code();
}
<|endoftext|>


<commit_before>/*
 * CX - C++ framework for general purpose development
 *
 * https://github.com/draede/cx
 *
 * Copyright (C) 2014 - 2017 draede, draede [at] outlook [dot] com
 *
 * Released under the MIT License.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "CX/Platform.hpp"

#if defined(CX_OS_WINDOWS)

#include "CX/Sys/Event.hpp"
#include "CX/Status.hpp"

namespace CX
{

namespace Sys
{

Event::Event()
{
	m_hEvent = NULL;
}

Event::~Event()
{
	Destroy();
}

Status Event::Create(bool bManualReset/* = false*/, bool bInitialState/* = false*/)
{
	Destroy();

	if (NULL == (m_hEvent = CreateEventW(NULL, (BOOL)bManualReset, (BOOL)bInitialState, NULL)))
	{
		return Status(Status_OperationFailed, "CreateEventW failed with error {1}", (int)GetLastError());
	}

	return Status();
}

Status Event::Destroy()
{
	if (NULL != m_hEvent)
	{
		CloseHandle(m_hEvent);
		m_hEvent = NULL;
	}

	return Status();
}

bool Event::IsOK()
{
	return (NULL != m_hEvent);
}

Status Event::Set()
{
	if (NULL == m_hEvent)
	{
		return Status_NotInitialized;
	}
	if (!SetEvent(m_hEvent))
	{
		return Status(Status_OperationFailed, "SetEvent failed with error {1}", (int)GetLastError());
	}

	return Status();
}

Status Event::Reset()
{
	if (NULL == m_hEvent)
	{
		return Status_NotInitialized;
	}
	if (!ResetEvent(m_hEvent))
	{
		return Status(Status_OperationFailed, "ResetEvent failed with error {1}", (int)GetLastError());
	}

	return Status();
}

Event::WaitResult Event::Wait(UInt32 cTimeout/* = 0xFFFFFFFF*/)
{
	if (NULL == m_hEvent)
	{
		return Wait_Error;
	}

	DWORD dwRet;

	dwRet = WaitForSingleObject(m_hEvent, (DWORD)cTimeout);

	if (WAIT_FAILED == dwRet || WAIT_ABANDONED == dwRet)
	{
		return Wait_Error;
	}
	if (WAIT_TIMEOUT == dwRet)
	{
		return Wait_Timeout;
	}

	return Wait_OK;
}

Event::WaitResult Event::WaitForMultipleEvents(Event **events, Size cCount, bool bWaitAll, Size *pcIndex,
                                               UInt32 cTimeout/* = 0xFFFFFFFF*/)
{
	if (0 == cCount || 64 < cCount)
	{
		return Wait_Error;
	}

	HANDLE     handles[64];
	WaitResult nRes;
	DWORD      dwRet;

	nRes = Wait_OK;
	for (;;)
	{
		for (Size i = 0; i < cCount; i++)
		{
			if (NULL == events[i]->m_hEvent)
			{
				nRes = Wait_Error;

				break;
			}
			handles[i] = events[i]->m_hEvent;
		}
		if (Wait_OK != nRes)
		{
			break;
		}
		dwRet = WaitForMultipleObjects((DWORD)cCount, handles, (BOOL)bWaitAll, (DWORD)cTimeout);
		if (WAIT_TIMEOUT == dwRet)
		{
			dwRet = Wait_Timeout;
		}
		else
		if (dwRet >= WAIT_ABANDONED_0)
		{
			return Wait_Error;
		}
		else
		{
			*pcIndex = dwRet - WAIT_OBJECT_0;
		}

		break;
	}

	return nRes;
}

}//namespace Sys

}//namespace CX

#endif

<commit_msg>Fixed Event::WaitForMultipleEvents returning wrong code (Wait_OK) in case of timeout (Wait_Timeout)<commit_after>/*
 * CX - C++ framework for general purpose development
 *
 * https://github.com/draede/cx
 *
 * Copyright (C) 2014 - 2017 draede, draede [at] outlook [dot] com
 *
 * Released under the MIT License.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "CX/Platform.hpp"

#if defined(CX_OS_WINDOWS)

#include "CX/Sys/Event.hpp"
#include "CX/Status.hpp"

namespace CX
{

namespace Sys
{

Event::Event()
{
	m_hEvent = NULL;
}

Event::~Event()
{
	Destroy();
}

Status Event::Create(bool bManualReset/* = false*/, bool bInitialState/* = false*/)
{
	Destroy();

	if (NULL == (m_hEvent = CreateEventW(NULL, (BOOL)bManualReset, (BOOL)bInitialState, NULL)))
	{
		return Status(Status_OperationFailed, "CreateEventW failed with error {1}", (int)GetLastError());
	}

	return Status();
}

Status Event::Destroy()
{
	if (NULL != m_hEvent)
	{
		CloseHandle(m_hEvent);
		m_hEvent = NULL;
	}

	return Status();
}

bool Event::IsOK()
{
	return (NULL != m_hEvent);
}

Status Event::Set()
{
	if (NULL == m_hEvent)
	{
		return Status_NotInitialized;
	}
	if (!SetEvent(m_hEvent))
	{
		return Status(Status_OperationFailed, "SetEvent failed with error {1}", (int)GetLastError());
	}

	return Status();
}

Status Event::Reset()
{
	if (NULL == m_hEvent)
	{
		return Status_NotInitialized;
	}
	if (!ResetEvent(m_hEvent))
	{
		return Status(Status_OperationFailed, "ResetEvent failed with error {1}", (int)GetLastError());
	}

	return Status();
}

Event::WaitResult Event::Wait(UInt32 cTimeout/* = 0xFFFFFFFF*/)
{
	if (NULL == m_hEvent)
	{
		return Wait_Error;
	}

	DWORD dwRet;

	dwRet = WaitForSingleObject(m_hEvent, (DWORD)cTimeout);

	if (WAIT_FAILED == dwRet || WAIT_ABANDONED == dwRet)
	{
		return Wait_Error;
	}
	if (WAIT_TIMEOUT == dwRet)
	{
		return Wait_Timeout;
	}

	return Wait_OK;
}

Event::WaitResult Event::WaitForMultipleEvents(Event **events, Size cCount, bool bWaitAll, Size *pcIndex,
                                               UInt32 cTimeout/* = 0xFFFFFFFF*/)
{
	if (0 == cCount || 64 < cCount)
	{
		return Wait_Error;
	}

	HANDLE     handles[64];
	WaitResult nRes;
	DWORD      dwRet;

	nRes = Wait_OK;
	for (;;)
	{
		for (Size i = 0; i < cCount; i++)
		{
			if (NULL == events[i]->m_hEvent)
			{
				nRes = Wait_Error;

				break;
			}
			handles[i] = events[i]->m_hEvent;
		}
		if (Wait_OK != nRes)
		{
			break;
		}
		dwRet = WaitForMultipleObjects((DWORD)cCount, handles, (BOOL)bWaitAll, (DWORD)cTimeout);
		if (WAIT_TIMEOUT == dwRet)
		{
			nRes = Wait_Timeout;
		}
		else
		if (dwRet >= WAIT_ABANDONED_0)
		{
			nRes = Wait_Error;
		}
		else
		{
			*pcIndex = dwRet - WAIT_OBJECT_0;
		}

		break;
	}

	return nRes;
}

}//namespace Sys

}//namespace CX

#endif

<|endoftext|>


<commit_before>#include "XMLFileSerializer.h"
#include "..\Helpers\Helpers.h"
#include "XMLContainer.h"

namespace star
{
	XMLFileSerializer::XMLFileSerializer(const tstring & path)
		: m_File(path)
	{

	}

	XMLFileSerializer::~XMLFileSerializer() {}

	void XMLFileSerializer::Write(
		XMLContainer & container,
		DirectoryMode mode
		)
	{
		tstring buffer = WriteFile(container);
		WriteTextFile(m_File, buffer, mode);
	}

	void XMLFileSerializer::Write(
			XMLContainer & container,
			const tstring & binaryPath,
			DirectoryMode mode
			)
	{
		container.Serialize(binaryPath, mode);
	}

	tstring XMLFileSerializer::WriteFile(XMLContainer & container)
	{
		tstringstream strstrResult;
		strstrResult << _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") << std::endl;
		uint32 tabs(0);
		WriteChild(strstrResult, container, tabs);

		return strstrResult.str();
	}

	void XMLFileSerializer::WriteAtributes(tstringstream & strstr, XMLContainer & element)
	{
		auto attributes = element.GetAttributes();
		for(auto attribute : attributes)
		{
			strstr << _T(" ") << attribute.first << _T("=\"") << attribute.second << _T("\"");
		}
	}

	void XMLFileSerializer::WriteChild(tstringstream & strstr, XMLContainer & element, uint32 & tabs)
	{
		strstr << GetTabString(tabs) << _T("<") << element.GetName();
		WriteAtributes(strstr, element);
		if(element.size() == 0 && element.GetValue() == EMPTY_STRING)
		{
			strstr << _T("/>") << std::endl;
		}
		else
		{
			strstr << _T(">");
			if(element.GetValue() != EMPTY_STRING)
			{
				strstr << element.GetValue();
				strstr << _T("</") << element.GetName();
				strstr << _T(">") << std::endl;
			}
			else if(element.size() > 0)
			{
				++tabs;
				strstr << std::endl;
				for(auto child : element)
				{
					XMLContainer child_value;
					child_value = *(child.second);
					WriteChild(strstr, child_value, tabs);
				}
				--tabs;
				strstr << GetTabString(tabs) << _T("</") << element.GetName() << _T(">") << std::endl;
			}
		}
	}

	tstring XMLFileSerializer::GetTabString(uint32 & tabs)
	{
		tstring tab_string(EMPTY_STRING);
		for(uint32 i = 0 ; i < tabs ; ++i)
		{
			tab_string += TAB;
		}
		return tab_string;
	}
}
<commit_msg>HotFix that fixes a bug when writing with a binary path.<commit_after>#include "XMLFileSerializer.h"
#include "..\Helpers\Helpers.h"
#include "XMLContainer.h"

namespace star
{
	XMLFileSerializer::XMLFileSerializer(const tstring & path)
		: m_File(path)
	{

	}

	XMLFileSerializer::~XMLFileSerializer() {}

	void XMLFileSerializer::Write(
		XMLContainer & container,
		DirectoryMode mode
		)
	{
		tstring buffer = WriteFile(container);
		WriteTextFile(m_File, buffer, mode);
	}

	void XMLFileSerializer::Write(
			XMLContainer & container,
			const tstring & binaryPath,
			DirectoryMode mode
			)
	{
		Write(container, mode);
		container.Serialize(binaryPath, mode);
	}

	tstring XMLFileSerializer::WriteFile(XMLContainer & container)
	{
		tstringstream strstrResult;
		strstrResult << _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") << std::endl;
		uint32 tabs(0);
		WriteChild(strstrResult, container, tabs);

		return strstrResult.str();
	}

	void XMLFileSerializer::WriteAtributes(tstringstream & strstr, XMLContainer & element)
	{
		auto attributes = element.GetAttributes();
		for(auto attribute : attributes)
		{
			strstr << _T(" ") << attribute.first << _T("=\"") << attribute.second << _T("\"");
		}
	}

	void XMLFileSerializer::WriteChild(tstringstream & strstr, XMLContainer & element, uint32 & tabs)
	{
		strstr << GetTabString(tabs) << _T("<") << element.GetName();
		WriteAtributes(strstr, element);
		if(element.size() == 0 && element.GetValue() == EMPTY_STRING)
		{
			strstr << _T("/>") << std::endl;
		}
		else
		{
			strstr << _T(">");
			if(element.GetValue() != EMPTY_STRING)
			{
				strstr << element.GetValue();
				strstr << _T("</") << element.GetName();
				strstr << _T(">") << std::endl;
			}
			else if(element.size() > 0)
			{
				++tabs;
				strstr << std::endl;
				for(auto child : element)
				{
					XMLContainer child_value;
					child_value = *(child.second);
					WriteChild(strstr, child_value, tabs);
				}
				--tabs;
				strstr << GetTabString(tabs) << _T("</") << element.GetName() << _T(">") << std::endl;
			}
		}
	}

	tstring XMLFileSerializer::GetTabString(uint32 & tabs)
	{
		tstring tab_string(EMPTY_STRING);
		for(uint32 i = 0 ; i < tabs ; ++i)
		{
			tab_string += TAB;
		}
		return tab_string;
	}
}
<|endoftext|>


<commit_before>// Copyright 2018, Intel Corp.

#include <gmock/gmock.h>
#include <google/protobuf/util/json_util.h>

#include "tile/codegen/stencil.h"
#include "tile/codegen/tile.h"
#include "tile/codegen/vm.h"
#include "tile/lang/compose.h"
#include "tile/lang/gen_stripe.h"
#include "tile/lib/lib.h"
#include "tile/stripe/stripe.h"

using ::testing::ContainerEq;
using ::testing::Eq;

namespace vertexai {
namespace tile {
namespace codegen {
namespace test {

namespace {

using plaidml::edsl::TensorShape;

template <typename T>
T ParseProtoJson(const std::string& str) {
  T proto;
  google::protobuf::util::JsonStringToMessage(str, &proto);
  return proto;
}

std::map<std::string, std::vector<float>> MakeMatMulTestData() {
  std::map<std::string, std::vector<float>> data = {
      {"A",
       {
           1, 2, 3, 4, 5,  //
           4, 5, 6, 7, 8,  //
           7, 8, 9, 7, 8,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
       }},
      {"B",
       {
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
       }},
      {"C",
       {
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
       }},
  };
  return data;
}

std::vector<float> kMatMulExpected = {
    15, 30, 45,  15, 30,  //
    30, 60, 90,  30, 60,  //
    39, 78, 117, 39, 78,  //
    9,  18, 27,  9,  18,  //
    9,  18, 27,  9,  18,  //
};

std::vector<float> kConv1dExpected = {
    45, 90,  135, 45, 90,   //
    84, 168, 252, 84, 168,  //
    78, 156, 234, 78, 156,  //
    57, 114, 171, 57, 114,  //
    18, 36,  54,  18, 36,   //
};

}  // namespace

TEST(Codegen, ApplyTile) {
  size_t dim = sqrt(kMatMulExpected.size());
  auto runinfo = lib::LoadMatMul("matmul",                                       //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {dim, dim}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {dim, dim}));
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto data = MakeMatMulTestData();

  IVLOG(2, "Before>\n" << *program->entry);

  ExecuteProgram(*program->entry, &data);

  IVLOG(2, "A: " << data["A"]);
  IVLOG(2, "B: " << data["B"]);
  IVLOG(2, "C: " << data["C"]);
  EXPECT_THAT(data["C"], ContainerEq(kMatMulExpected));

  auto kernel = main->SubBlock(0);
  ApplyTile(kernel.get(), {5, 2, 2});
  auto inner = kernel->SubBlock(0);
  inner->name = "inner";
  ApplyTile(inner.get(), {5, 3, 2, 1, 1});
  auto innermost = inner->SubBlock(0);
  innermost->name = "innermost";
  ApplyTile(kernel.get(), {5, 2, 2});
  kernel->SubBlock(0)->name = "outer";

  IVLOG(2, "After>\n" << *program->entry);

  std::fill(data["C"].begin(), data["C"].end(), 0);
  ExecuteProgram(*program->entry, &data);

  IVLOG(2, "A: " << data["A"]);
  IVLOG(2, "B: " << data["B"]);
  IVLOG(2, "C: " << data["C"]);
  EXPECT_THAT(data["C"], ContainerEq(kMatMulExpected));
}

TEST(Stencil, MatchMatMul) {
  auto spec = ParseProtoJson<proto::Stencil>(R"(
    {
      "startup_cost": 32,
      "idxs": [
        { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
        { "name": "x", "size": 16, "outs": [ -1 ], "ins": [  0, -1 ] },
        { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
      ]
    }
  )");

  const auto DIM = 100;
  auto runinfo = lib::LoadMatMul("matmul",                                       //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}));
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto kernel = main->SubBlock(0);

  IVLOG(2, *kernel);

  auto match = FindBestStencil({spec}, kernel.get());
  ASSERT_TRUE(match);
  IVLOG(1, "Best match: " << *match);
  StencilMatch expected{
      1255968,  // total
      {
          {"k", "c", 100},
          {"m", "k", 16},
          {"n", "x", 16},
      }  // idxs
  };
  EXPECT_THAT(*match, Eq(expected));
}

TEST(Stencil, MatchConv1D) {
  auto spec = ParseProtoJson<proto::Stencil>(R"(
    {
      "startup_cost": 32,
      "idxs": [
        { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
        { "name": "x", "size": 16, "outs": [ -1 ], "ins": [  0, -1 ] },
        { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
      ]
    }
  )");

  auto runinfo = lib::LoadConv1d("conv",                                           //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {1, 100, 64}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {3, 64, 64}),   //
                                 {1, 100, 64});
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto kernel = main->SubBlock(0);

  IVLOG(2, *kernel);

  auto match = FindBestStencil({spec}, kernel.get());
  ASSERT_TRUE(match);
  IVLOG(1, "Best match: " << *match);
  StencilMatch expected{
      1378944,  // total
      {
          {"ci", "c", 64},
          {"co", "k", 16},
          {"k0", "*", 1},
          {"n", "*", 1},
          {"x0", "x", 16},
      }  // idxs
  };
  EXPECT_THAT(*match, Eq(expected));
}

TEST(Stencil, MatchConv2D) {
  auto options = ParseProtoJson<proto::StencilPass>(R"(
    {
      "stencils": [
        {
          "startup_cost": 32,
          "idxs": [
            { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
            { "name": "x", "size": 16, "outs": [ -1 ], "ins": [  0, -1 ] },
            { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
          ]
        },
        {
          "startup_cost": 32,
          "idxs": [
            { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
            { "name": "x", "size":  4, "outs": [ -1 ], "ins": [  0, -1 ] },
            { "name": "y", "size":  4, "outs": [ -1 ], "ins": [  0, -1 ] },
            { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
          ]
        }
      ]
    }
  )");
  std::vector<proto::Stencil> specs;
  for (const auto& stencil : options.stencils()) {
    specs.push_back(stencil);
  }

  auto runinfo = lib::LoadConv2d("conv",                                                //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {1, 100, 100, 56}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {3, 3, 56, 56}),     //
                                 {1, 100, 100, 56});                                    //
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto kernel = main->SubBlock(0);

  IVLOG(2, "\n" << *kernel);

  auto match = FindBestStencil(specs, kernel.get());
  ASSERT_TRUE(match);
  IVLOG(1, "Best match: " << *match);
  StencilMatch expected{
      323280000,  // total
      {
          {"ci", "c", 56},
          {"co", "k", 16},
          {"k0", "*", 1},
          {"k1", "*", 1},
          {"n", "*", 1},
          {"x0", "x", 4},
          {"x1", "y", 4},
      }  // idxs
  };
  EXPECT_THAT(*match, Eq(expected));
}

TEST(Stencil, Pass) {
  auto options = ParseProtoJson<proto::StencilPass>(R"(
    {
      "reqs": ["agg_op_add", "comb_op_mul"],
      "startup_cost": 32,
      "idxs": [
        { "name": "k", "size":  2, "outs": [ -1 ], "ins": [ -1,  0 ] },
        { "name": "x", "size":  2, "outs": [ -1 ], "ins": [  0, -1 ] },
        { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
      ]
    }
  )");

  const auto DIM = 5;
  auto runinfo = lib::LoadMatMul("matmul",                                       //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}));
  auto program = GenerateStripe(runinfo);
  CompilerState state(program);
  StencilPass(options).Apply(&state);
  IVLOG(2, "\n" << *program->entry);

  auto data = MakeMatMulTestData();
  ExecuteProgram(*program->entry, &data);

  IVLOG(2, "A: " << data["A"]);
  IVLOG(2, "B: " << data["B"]);
  IVLOG(2, "C: " << data["C"]);
  EXPECT_THAT(data["C"], ContainerEq(kMatMulExpected));
}

TEST(Codegen, TilePassBroadcast) {
  lang::RunInfo runinfo;
  runinfo.program_name = "broadcast";
  runinfo.code = "function (A, B) -> (C) { C = add(A, B); }";
  runinfo.input_shapes.emplace("A", tile::SimpleShape(DataType::FLOAT32, {1, 112, 112, 32}));
  runinfo.input_shapes.emplace("B", tile::SimpleShape(DataType::FLOAT32, {32}));
  runinfo.output_shapes.emplace("C", tile::SimpleShape(DataType::FLOAT32, {1, 112, 112, 32}));
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);

  IVLOG(2, "\n" << *program->entry);
}

}  // namespace test
}  // namespace codegen
}  // namespace tile
}  // namespace vertexai
<commit_msg>Minor tile test.cc tweaks<commit_after>// Copyright 2018, Intel Corp.

#include <gmock/gmock.h>
#include <google/protobuf/util/json_util.h>

#include "tile/codegen/stencil.h"
#include "tile/codegen/tile.h"
#include "tile/codegen/vm.h"
#include "tile/lang/compose.h"
#include "tile/lang/gen_stripe.h"
#include "tile/lib/lib.h"
#include "tile/stripe/stripe.h"

using ::testing::ContainerEq;
using ::testing::Eq;

namespace vertexai {
namespace tile {
namespace codegen {
namespace test {

namespace {

using plaidml::edsl::TensorShape;

template <typename T>
T ParseProtoJson(const std::string& str) {
  T proto;
  google::protobuf::util::JsonStringToMessage(str, &proto);
  return proto;
}

std::map<std::string, std::vector<float>> MakeMatMulTestData() {
  std::map<std::string, std::vector<float>> data = {
      {"A",
       {
           1, 2, 3, 4, 5,  //
           4, 5, 6, 7, 8,  //
           7, 8, 9, 7, 8,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
       }},
      {"B",
       {
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
           1, 2, 3, 1, 2,  //
       }},
      {"C",
       {
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
           0, 0, 0, 0, 0,  //
       }},
  };
  return data;
}

std::vector<float> kMatMulExpected = {
    15, 30, 45,  15, 30,  //
    30, 60, 90,  30, 60,  //
    39, 78, 117, 39, 78,  //
    9,  18, 27,  9,  18,  //
    9,  18, 27,  9,  18,  //
};

std::vector<float> kConv1dExpected = {
    45, 90,  135, 45, 90,   //
    84, 168, 252, 84, 168,  //
    78, 156, 234, 78, 156,  //
    57, 114, 171, 57, 114,  //
    18, 36,  54,  18, 36,   //
};

}  // namespace

TEST(Codegen, ApplyTile) {
  size_t dim = sqrt(kMatMulExpected.size());
  auto runinfo = lib::LoadMatMul("matmul",                                       //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {dim, dim}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {dim, dim}));
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto data = MakeMatMulTestData();

  IVLOG(2, "Before>\n" << *program->entry);

  ExecuteProgram(*program->entry, &data);

  IVLOG(2, "A: " << data["A"]);
  IVLOG(2, "B: " << data["B"]);
  IVLOG(2, "C: " << data["C"]);
  EXPECT_THAT(data["C"], ContainerEq(kMatMulExpected));

  auto kernel = main->SubBlock(0);
  ApplyTile(kernel.get(), {5, 2, 2});
  auto inner = kernel->SubBlock(0);
  inner->name = "inner";
  ApplyTile(inner.get(), {5, 3, 2, 1, 1});
  auto innermost = inner->SubBlock(0);
  innermost->name = "innermost";
  ApplyTile(kernel.get(), {5, 2, 2});
  kernel->SubBlock(0)->name = "outer";

  IVLOG(2, "After>\n" << *program->entry);

  std::fill(data["C"].begin(), data["C"].end(), 0.f);
  ExecuteProgram(*program->entry, &data);

  IVLOG(2, "A: " << data["A"]);
  IVLOG(2, "B: " << data["B"]);
  IVLOG(2, "C: " << data["C"]);
  EXPECT_THAT(data["C"], ContainerEq(kMatMulExpected));
}

TEST(Stencil, MatchMatMul) {
  auto spec = ParseProtoJson<proto::Stencil>(R"(
    {
      "startup_cost": 32,
      "idxs": [
        { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
        { "name": "x", "size": 16, "outs": [ -1 ], "ins": [  0, -1 ] },
        { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
      ]
    }
  )");

  const std::uint64_t DIM = 100;
  auto runinfo = lib::LoadMatMul("matmul",                                       //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}));
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto kernel = main->SubBlock(0);

  IVLOG(2, *kernel);

  auto match = FindBestStencil({spec}, kernel.get());
  ASSERT_TRUE(match);
  IVLOG(1, "Best match: " << *match);
  StencilMatch expected{
      1255968,  // total
      {
          {"k", "c", 100},
          {"m", "k", 16},
          {"n", "x", 16},
      }  // idxs
  };
  EXPECT_THAT(*match, Eq(expected));
}

TEST(Stencil, MatchConv1D) {
  auto spec = ParseProtoJson<proto::Stencil>(R"(
    {
      "startup_cost": 32,
      "idxs": [
        { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
        { "name": "x", "size": 16, "outs": [ -1 ], "ins": [  0, -1 ] },
        { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
      ]
    }
  )");

  auto runinfo = lib::LoadConv1d("conv",                                           //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {1, 100, 64}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {3, 64, 64}),   //
                                 {1, 100, 64});
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto kernel = main->SubBlock(0);

  IVLOG(2, *kernel);

  auto match = FindBestStencil({spec}, kernel.get());
  ASSERT_TRUE(match);
  IVLOG(1, "Best match: " << *match);
  StencilMatch expected{
      1378944,  // total
      {
          {"ci", "c", 64},
          {"co", "k", 16},
          {"k0", "*", 1},
          {"n", "*", 1},
          {"x0", "x", 16},
      }  // idxs
  };
  EXPECT_THAT(*match, Eq(expected));
}

TEST(Stencil, MatchConv2D) {
  auto options = ParseProtoJson<proto::StencilPass>(R"(
    {
      "stencils": [
        {
          "startup_cost": 32,
          "idxs": [
            { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
            { "name": "x", "size": 16, "outs": [ -1 ], "ins": [  0, -1 ] },
            { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
          ]
        },
        {
          "startup_cost": 32,
          "idxs": [
            { "name": "k", "size": 16, "outs": [ -1 ], "ins": [ -1,  0 ] },
            { "name": "x", "size":  4, "outs": [ -1 ], "ins": [  0, -1 ] },
            { "name": "y", "size":  4, "outs": [ -1 ], "ins": [  0, -1 ] },
            { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
          ]
        }
      ]
    }
  )");
  std::vector<proto::Stencil> specs;
  for (const auto& stencil : options.stencils()) {
    specs.push_back(stencil);
  }

  auto runinfo = lib::LoadConv2d("conv",                                                //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {1, 100, 100, 56}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {3, 3, 56, 56}),     //
                                 {1, 100, 100, 56});                                    //
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);
  auto kernel = main->SubBlock(0);

  IVLOG(2, "\n" << *kernel);

  auto match = FindBestStencil(specs, kernel.get());
  ASSERT_TRUE(match);
  IVLOG(1, "Best match: " << *match);
  StencilMatch expected{
      323280000,  // total
      {
          {"ci", "c", 56},
          {"co", "k", 16},
          {"k0", "*", 1},
          {"k1", "*", 1},
          {"n", "*", 1},
          {"x0", "x", 4},
          {"x1", "y", 4},
      }  // idxs
  };
  EXPECT_THAT(*match, Eq(expected));
}

TEST(Stencil, Pass) {
  auto options = ParseProtoJson<proto::StencilPass>(R"(
    {
      "reqs": ["agg_op_add", "comb_op_mul"],
      "startup_cost": 32,
      "idxs": [
        { "name": "k", "size":  2, "outs": [ -1 ], "ins": [ -1,  0 ] },
        { "name": "x", "size":  2, "outs": [ -1 ], "ins": [  0, -1 ] },
        { "name": "c", "size": -1, "outs": [  0 ], "ins": [ -1, -1 ] },
      ]
    }
  )");

  const std::uint64_t DIM = 5;
  auto runinfo = lib::LoadMatMul("matmul",                                       //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}),  //
                                 TensorShape(PLAIDML_DATA_FLOAT32, {DIM, DIM}));
  auto program = GenerateStripe(runinfo);
  CompilerState state(program);
  StencilPass(options).Apply(&state);
  IVLOG(2, "\n" << *program->entry);

  auto data = MakeMatMulTestData();
  ExecuteProgram(*program->entry, &data);

  IVLOG(2, "A: " << data["A"]);
  IVLOG(2, "B: " << data["B"]);
  IVLOG(2, "C: " << data["C"]);
  EXPECT_THAT(data["C"], ContainerEq(kMatMulExpected));
}

TEST(Codegen, TilePassBroadcast) {
  lang::RunInfo runinfo;
  runinfo.program_name = "broadcast";
  runinfo.code = "function (A, B) -> (C) { C = add(A, B); }";
  runinfo.input_shapes.emplace("A", tile::SimpleShape(DataType::FLOAT32, {1, 112, 112, 32}));
  runinfo.input_shapes.emplace("B", tile::SimpleShape(DataType::FLOAT32, {32}));
  runinfo.output_shapes.emplace("C", tile::SimpleShape(DataType::FLOAT32, {1, 112, 112, 32}));
  auto program = GenerateStripe(runinfo);
  auto main = program->entry->SubBlock(0);

  IVLOG(2, "\n" << *program->entry);
}

}  // namespace test
}  // namespace codegen
}  // namespace tile
}  // namespace vertexai
<|endoftext|>